Search code examples
c#.netrhino-mocks

Mocking collections with Rhino Mocks


So this is something I guess many people want to do, mock a collection. In the past with Rhino I have done this with something like:

var col_mock = MockRepository.GenerateMock<ICustomCollection>(); // returns ICustom let's say
List<ICustom> col_real = new List<ICustom>();
col_real.Add(custom_mock1);
col_real.Add(custom_mock2);
col_real.Add(custom_mock3);
col_mock.Stub(x => x.GetEnumerator()).Return(col_real.GetEnumerator());

So yup this works fine, when you foreach col_mock you get the mocked (custom_mock1 etc.) objects back. Great! We have successfully mocked a custom collection by using a typed list to actually store a load of mocked objects.

The problem is, you can only do this once! you can only foreach this collection once. Does anyone know (without creating an actual custom collection...) how I can achieve the mocking of a custom collection which can be iterated more than once?


Solution

  • The problem is that the enumerator is only instantiated once, when you call Return. Then it returns the same instance which is already at the end of the list after the first foreach.

    You need to instantiate a new enumerator each time when GetEnumerator is called. You could use WhenCalled to do so.

    Return is still needed, because Rhino Mocks will complain when it is missing. But it doesn't matter what you pass as argument.

    [TestMethod]
    public void GetEnumerator()
    {
        IList<int> col_mock = MockRepository.GenerateMock<IList<int>>();
        List<int> col_real = new List<int>();
        col_real.Add(1);
        col_real.Add(2);
        col_real.Add(3);
        col_mock
            .Stub(x => x.GetEnumerator())
            // create new enumerator instance for each call
            .WhenCalled(call => call.ReturnValue = col_real.GetEnumerator())
            .Return(null) // is ignored, but needed for Rhinos validation
            .Repeat.Any();
    
        foreach (int i in col_mock)
        {
        }
    
        int count = 0;
        foreach (int i in col_mock)
        {
            count++;
        }
        Assert.AreSame(3, count);
    }