Rhino Mock 用于执行 yield return。

4

我正在尝试编写一条单元测试以检查解析错误。 我从文件流中输入数据,解析它并使用yield return返回解析结果,然后将其传递给数据层进行批量插入。

我遇到了模拟数据层调用的问题。 由于它是被模拟出来的,它实际上永远不会枚举yield return的值,因此我的解析方法永远不会执行。

public class Processor
{
    public IUnityContainer Container { get; set; }

    public void ProcessFile(Stream stream)
    {
        var datamanager = Container.Resolve<IDataManager>();                                            
        var things = Parse(stream);        
        datamanager.Save(things);                                
    }

    IEnumerable<string> Parse(Stream stream)
    {
        var sr = new StreamReader(stream);
        while (!sr.EndOfStream)
        {
            string line = sr.ReadLine();
            // do magic
            yield return line;
        }
    }
}

我尝试了类似这样的东西,显然不起作用。
[TestMethod]        
[ExpectedException(typeof(ApplicationException))]
public void ProcessFile_InvalidInput_ThrowsException()
{
    var mock = new MockRepository();

    var stream = new MemoryStream();
    var streamWriter = new StreamWriter(stream);                
    streamWriter.WriteLine("\\:fail");
    streamWriter.Flush();
    stream.Position = 0;

    var datamanager = mock.Stub<IDataManager>();                        
    TestContainer.RegisterInstance(datamanager);

    var repos = new ProcessingRepository();
    TestContainer.BuildUp(repos);

    using (mock.Record())
    {                         
        Expect.Call(file.InputStream).Return(stream);                            
        Expect.Call(delegate() { repos.Save(new List<string>()) }).IgnoreArguments();
    }
    using (mock.Playback())
    {
        repos.ProcessFile(stream);
    }
}
1个回答

3
一种最佳的解决方案是将 "//do magic" 中发生的事情放在一个单独的方法中,以便可以单独进行单元测试--而无需从处理 StreamReader 的 while 循环内部调用它。
你看到的问题是由于枚举的惰性求值引起的。由于您的测试代码实际上没有枚举 "things",因此用于处理迭代器块的状态机从未被处理。
为了实际执行 Parse 方法中的逻辑,您需要使项目按顺序枚举。您可以使用 Rhino.Mocks 的 "WhenCalled" 方法来实现这一点(我展示 AAA 语法,因为我不记得如何使用 record/replay 语义):
注意:这是未经测试的代码。
datamanager.Stub(d => d.Save(null)).IgnoreArguments().WhenCalled(m => int count = ((IEnumerable<string>)m.Arguments[0]).Count());

当调用存根上的 Save 方法时,会传递一个包含有关调用方法的信息的参数(m)给“WhenCalled”。获取第一个参数(things),将其强制转换为 IEnumerable<string> 并获取其计数。这将强制对可枚举对象进行求值。

WhenCalled正是我所需要的,谢谢! - bmancini

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接