Using Rhino.Mocks WhenCalled(...) - remember to Return(...)!
Today I was working with a repository that looked like this:
[csharp]public interface IRepository { … IQueryable<T> Get<T>(); IQueryable<T> Get<T>(Expression<Func<T, bool>> predicate); …. }[/csharp]
This allows consumers of the repo to shorten
[csharp gutter=”false”]var result = repo.Get<IWidget>().Where(w => w.Price > 10.00m);[/csharp]
to this:
[csharp gutter=”false”]var result = repo.Get<IWidget>(w => w.Price > 10.00m);[/csharp]
Not complicated but sure convenient when you are issuing a lot of queries against the repo.
In one test I had mocked the repo like so:
[csharp]List<IWidget> fakeWidgets;
IRepository mockRepo = MockRepository.GenerateMock<IRepostory>();
mockRepo.Expect(r => r.Get<IWidget>()).Return(fakeWidgets.AsQueryable());[/csharp]
What this does is create a fake IRepository instance and then set it up so that when any consumer calls Get<IWidget() it returns our collection of fakeWidgets. The AsQueryable() call on the end is to transform our fake List<IWidget> into the IQueryable<IWidget> returned by Get<IWidget>().
That worked great for calls like
[csharp gutter=”false”]var result = repo.Get<IWidget>().Where(… some predicate …);[/csharp]
but failed, predictably, with a NullReferenceException on calls like
[csharp gutter=”false”]var result = repo.Get<IWidget>(… some predicate …);[/csharp]
So here’s how I first set up an expectation that would delegate this predicate:
[csharp]List<IWidget> fakeWidgets;
IRepository mockRepo = MockRepository.GenerateMock<IRepostory>();
mockRepo.Expect(r => r.Get<IWidget>()).Return(fakeWidgets.AsQueryable());
mockRepo.Expect(r => r.Get<IWidget>(Arg<Expression<Func<IWidget, bool>>>.Is.Anything)) .WhenCalled(invocation => { var predicate = invocation.Arguments.First() as Expression<Func<IWidget, bool>>; invocation.ReturnValue = mockRepo.Get<IWidget>().Where(predicate); });[/csharp]
Don't let the angle-brackets scare you; Arg<Expression<Func<IWidget, bool>>>.Is.Anything is simply Rhino Mocks’ way of saying accept any argument which looks like a function that takes an IWidget and returns a bool.
Then magic of the WhenCalled(…) method in line 8 is that it lets you manipulate a model of the actual method invocation which you are expecting. In this case on line 10 I’m grabbing that predicate argument matched in line 7 and then, on line 11, applying the predicate to the previously mocked Get<IWidget>() and stuffing it back into the method invocation as the actual ReturnValue.
What this effectively accomplishes is to make a call to the Get<IWidget>(predicate) method on that mocked IRepository act like a call to the Get<IWidget>() that has had the predicate applied.
Method … requires a return value or an exception to throw.
When I ran my test I got this error:
Method ‘IRepository.Get<IWidget>(anything);’ requires a return value or an exception to throw.
It took me a while to make sense of this message.
I had set the ReturnValue of the MethodInvocation passed to WhenCalled(...) so I figured Rhino Mocks knew the return value and I could safely drop the explicit Return(…) call that ends line 5
So what was going on?
Return(…) is required
Turns out Google and this post by Carlos Mendible came to my rescue.
The important part is that Rhino Mocks requires a Return(...) call at the end of an Expect(...) chain in order to determine the type of the return result.
Hence my delegating WhenCalled(...) code had to look like this:
[csharp highlight=”8”]mockRepo.Expect(r => r.Get<IWidget>(Arg<Expression<Func<IWidget, bool>>>.Is.Anything)) .WhenCalled(invocation => { var predicate = invocation.Arguments.First() as Expression<Func<IWidget, bool>>; invocation.ReturnValue = mockRepo.Get<IWidget>().Where(predicate); }) .Return(Enumerable.Empty<IWidget>().AsQueryable());[/csharp]
Now my calling client that used the shorter syntax behaves exactly as expected.