Search code examples
c#unit-testingtddmockingrhino-mocks

Mocking iterative behaviour


I have an interface with iterative behaviour, and I am having trouble Mocking that in Rhinomocks. The example interface and class is a very simple version of my problem.

Every time LineReader.Read() is called, the LineReader.CurrentLine() should return a different value -- the next line. This behaviour I haven't been able to reproduce in a mock so far. Thus, it has become a small hobby project of mine which I return to from time to time. I hope you can help me a step further.

internal class LineReader : ILineReader
{
    private readonly IList<string> _lines;
    private int _countOfLines;
    private int _place; 

    public LineReader(IList<string> 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);
    }

}

EDIT Incomplete unit test added:

    [Test]
    public void Test()
    {
        IList<string> lineListForMock = new List<string>()
                                            {
                                                "A",
                                                "B",
                                                "C"
                                            };

        MockRepository mockRepository = new MockRepository();
        ILineReader lineReader = mockRepository.Stub<ILineReader>();

        //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);


    }

Solution

  • This is all you need:

    var enumerator = new List<string> { "A", "B", "C" }.GetEnumerator();
    var lineReader = MockRepository.GenerateStub<ILineReader>();
    
    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());