Moq: Linq, Lambdas and Predicates applied to Mock Objects
Kzu and friends have a new pet project called Moq, which may be the coolest derivative open source project name ever. But, before I get into that...
There's lots of interesting Mock Object Frameworks out there. The ones that you'll always hear about (because they are awesome) are Rhino.Mocks and TypeMock (Full Disclosure: we used TypeMock at Corillian, my last job. Here's a Case Study that was done.)
Both frameworks are very powerful. Here's Phil Haack's post on mocking IHttpRequest and IHttpReponse in the new MVC Framework using Rhino Mocks. Here's Travis Illig using TypeMock to mock the actual HttpContext (not the MVC interface) earlier this year.
One of the things that often comes up when comparing Mock Frameworks, after their core capabilities, is their syntax.
Early Mocking frameworks like NMock (which isn't really used much anymore) mock interfaces and use a quasi-fluent interface that breaks down when you start referring to methods and properties using strings. Why is this bad? Well, for one it means when you refactor using tools like CodeRush or Resharper the system doesn't realize that a string referring to "Foo" means the method x.Foo(). For example, here's a snippet from NMock:
mocks = new Mockery(); ITransferFundsView mockView = mocks.NewMock<ITransferFundsView>(); Expect.Once.On(mockView).GetProperty("Amount").Will(Return.Value(200.00));
You get the idea. We're referring to a property "FromAccount" via a string passed into GetProperty, rather than in a strongly typed way.
RhinoMock is smarter, and might look like this snippet:
mockView = (ITransferFundsView)mocks.CreateType(typeof(ITransferFundsView));
See how much clearer it is to just call the property?
TypeMock is implemented as a profiler under the covers so it can do some pretty powerful stuff like "recording" your expectations do you can Tivo them back. So with TypeMock you'd do this using their "Natural TypeMock" syntax.:
using (RecordExpectations recorder = RecorderManager.StartRecording())
double foo = mockView.Ammount;
//the next time you call mockView.Ammount, it will return 200.00.
Either way, you can see why both RhinoMocks and TypeMock's syntaxs would be refactoring tool friendly. They compile against the real method signatures and properties so they can been "seen" by the tool. As for which one you like, that's a religious argument I won't get into, but depending on what you need, both are fine choices and they each have a very friendly syntax.
Why all this background? There's a new Mocking Framework in town, and it's C# 3.0 specific using LINQ Expression Trees and Lambda Expressions.
The same snippet in Moq might look like this:
var mockView = new Mock<ITransferFundsView>;
mockView.Expect(x => x.Amount).Returns(200.00);
Note the use of Generics for the Type ITransferFundsView and the interesting use of a Lambda expression to indicate a mocked call to the Amount property. Check out the Moq QuickStart for more interesting examples.
Here's another deeper, more interesting example that shows how lambdas might really be a great feature for any .NET Mock Framework. It's the "It" class combined with the power of predicates.
Itclass provides for a kind of wildcard support. There's an
IsRegex. The coolest one though is the plain
It.Ismethod that receives a predicate!mock.Expect(x => x.DoInt(It.Is<int>(i => i % 2 == 0))).Returns(1);
Here the mocked object will return the value 1 only if the integer passed to the DoInt method is an even number.
The cool thing about this approach is that you don't need the mocking library to provide all the filters you need, as you can simply pass a predicate for any condition you can dream of.
Slick. Moq is definitely a project to watch.
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
Yes, I'm a bit of a Rhino.Mocks fanboy... but I blame it on Phil - he's the one that pushed it on me in the first place. ;)
Expression tress are the best part of Linq.
In Moq it looks like this:
mock.Expect(x => x.DoInt(It.Is<int>(i => i % 2 == 0))).Returns(1);
and in Rhino Mocks it looks like this:
Expect.Call( () => foo.DoInt(0) ).Constraints( Is.Matching<int>( i => i % 2 == 0) ).Return(1);
This style is doable with C# 2.0 anonymous delegates, the alternative lamda syntax just makes it look cleaner.
All of these libraries are a bit like (in the famous old phrase) a dog walking on two legs, impressive we can do it at all. They stretch the host syntax further than it should go, but that's the best we can do until we get to more helpful languages.
I believe the source of the error is that apparently type inference does not work on method groups, as explained by Eric Lipert
I think making a new framework just for the new syntax feature is a bit of an overkill.
Comments are closed.
mockView = mocks.CreateMock<ITransferFundsView>();