模拟迭代行为

我有一个迭代行为的界面,我在Rhinomocks模拟它时遇到了麻烦。 示例接口和类是我的问题的一个非常简单的版本。

每次调用LineReader.Read()时,LineReader.CurrentLine()都应该返回一个不同的值 – 下一行。 到目前为止,我还没有能够在模拟中重现这种行为。 因此,它已成为我的一个小业余爱好项目,我不时回到这里。 我希望你能帮助我更进一步。

internal class LineReader : ILineReader { private readonly IList _lines; private int _countOfLines; private int _place; public LineReader(IList lines) { _lines = lines; _countOfLines = lines.Count; _place = 0; } public string CurrentLine() { if (_place<_countOfLines) { return _lines[_place]; } else { return null; } } public bool ReadLine() { _place++; return (_place < _countOfLines); } } 

编辑不完整的unit testing添加

  [Test] public void Test() { IList lineListForMock = new List() { "A", "B", "C" }; MockRepository mockRepository = new MockRepository(); ILineReader lineReader = mockRepository.Stub(); //Setup the values here mockRepository.ReplayAll(); bool read1 = lineReader.ReadLine(); Assert.That(read1, Is.True); Assert.That(lineReader.CurrentLine(), Is.EqualTo("A")); bool read2 = lineReader.ReadLine(); Assert.That(read2, Is.True); Assert.That(lineReader.CurrentLine(), Is.EqualTo("B")); bool read3 = lineReader.ReadLine(); Assert.That(read3, Is.True); Assert.That(lineReader.CurrentLine(), Is.EqualTo("C")); bool read1 = lineReader.ReadLine(); Assert.That(read1, Is.False); } 

这就是你所需要的:

 var enumerator = new List { "A", "B", "C" }.GetEnumerator(); var lineReader = MockRepository.GenerateStub(); lineReader.Stub(x => x.CurrentLine()) .Return("ignored") .WhenCalled(x => x.ReturnValue = enumerator.Current); lineReader.Stub(x => x.ReadLine()) .Return(false) // will be ignored .WhenCalled(x => x.ReturnValue = enumerator.MoveNext()); 

这似乎可以解决问题:

 [TestFixture] public sealed class TestIterativeRhinoReturn { private int _count; private int _countOfLines; private IList _lines; private string _currentLine; [SetUp] public void SetUp() { _count = -1; _lines= new List() { "A", "B", "C", null }; _countOfLines = _lines.Count; _currentLine = null; } [Test] public void Test() { MockRepository mockRepository = new MockRepository(); ILineReader lineReader = mockRepository.DynamicMock(); lineReader.Stub(r => r.ReadLine()).Callback(new ReadLineDelegate(ReadRecord)).Return(_count < _countOfLines); lineReader.Stub(r => r.CurrentLine()).Do(new CurrentStringDelegate(ReturnString)).Return(_currentLine); mockRepository.ReplayAll(); bool read1 = lineReader.ReadLine(); Assert.That(read1, Is.True); Assert.That(lineReader.CurrentLine(), Is.EqualTo("A")); bool read2 = lineReader.ReadLine(); Assert.That(read2, Is.True); Assert.That(lineReader.CurrentLine(), Is.EqualTo("B")); bool read3 = lineReader.ReadLine(); Assert.That(read3, Is.True); Assert.That(lineReader.CurrentLine(), Is.EqualTo("C")); bool read4 = lineReader.ReadLine(); Assert.That(read4, Is.False); Assert.That(lineReader.CurrentLine(), Is.Null); } public delegate bool ReadLineDelegate(); private bool ReadRecord() { _count++; return (_lines[_count]!=null); } public delegate string CurrentStringDelegate(); private string ReturnString() { return _lines[_count]; } 

注意线条:

  lineReader.Stub(r => r.ReadLine()).Callback(new ReadLineDelegate(ReadRecord)).Return(_count < _countOfLines); lineReader.Stub(r => r.CurrentLine()).Do(new CurrentStringDelegate(ReturnString)).Return(_currentLine); 

和Delegate方法ReadRecord()和ReturnString()。 现在,每次读取的返回值都会发生变化。

我不知道我是否有最新版本的rhino-mocks,但我的.Return方法没有采取委托/行动 – 这可能对你想要的东西有用。

但是,你似乎更接近基于状态的测试,所以也许只是创建自己的模拟实现进行测试(或存根,或假 – 你选择:)

然后,您可以控制您所追求的确切值。