Mocking delegates with Rhino Mocks

I recently found out that Rhino Mocks can mock delegates. Not that I didn’t think it couldn’t, it just never occurred to me to try. But it turns out to be quite nice for stubbing delegate calls or for checking they were called. Say we have the following class:

public class SomeClass {
    private readonly Func<int, int> _mapper;

    public SomeClass(Func<int, int> mapper) {
        _mapper = mapper;
    }

    public int DoSomething(int toThisInt) {
        return _mapper(toThisInt);
    }
}

Here’s an example of testing that a simple Func<int, int> delegate is called correctly by our class under test without using Rhino Mocks:

[Test]
public void ManualFakeDelegate() {
    //Arrange
    var wasCalled = false;
    var intMapped = 0;
    var expectedResult = 1234;
    Func<int, int> fakeMapper = i => {
                        wasCalled = true;
                        intMapped = i;
                        return expectedResult;
                    };
    var someClass = new SomeClass(fakeMapper);

    //Act
    var result = someClass.DoSomething(10);

    //Assert
    Assert.True(wasCalled);
    Assert.AreEqual(intMapped, 10);
    Assert.AreEqual(expectedResult, result);
}

Now using Rhino Mocks:

[Test]
public void MockingDelegates() {
    var stubMapper = MockRepository.GenerateStub<Func<int, int>>();
    var expectedResult = 1234;
    stubMapper.Stub(x => x(10)).Return(expectedResult);            
    var someClass = new SomeClass(stubMapper);

    var result = someClass.DoSomething(10);

    Assert.AreEqual(expectedResult, result);
}

We no longer have to maintain all that test state to assert against, nor do we need to create any fake delegate implementation. We can also use stubMapper.AssertWasCalled(x => x(10)), but in this case that is already tested implicitly through the stubbed call and assertion.

In the first case, we could move some more advanced logic into our fakeMapper to do more advanced parameter checking and avoid some of the extra state and assertions, but that is potentially error-prone and we get it for free with our mocking library.

As an aside, you can obviously also mock Action or Func, but the wasCalled/fakeMapper approach is probably easier in that case.

Not something I’ll need very often, but nice to know for those rare occasions were I do.

Comments