The coding blog of Alastair Smith, a software developer based in Cambridge, UK. Interested in DevOps, Azure, Kubernetes, .NET Core, and VueJS.
You may remember from my previous blog post on mocking frameworks that I’m a bit of a fan of this kind of tool. They’re great for simplifying unit testing, and can also help guide you in to writing better, more loosely-coupled code via Dependency Injection.
Last night I spent some time porting some of my unit tests for a side project I’m working on from NMock 2 to Moq 4 (currently in beta). My reasons for switching were three-fold: first, NMock can only mock interfaces which was causing problems with testing some parts of my code that relied on elements of the ASP.NET MVC framework; second, NMock is unable to support some of the newer features of .NET as it was written to target .NET 2.0 (whilst each version of Moq is matched to the respective version of .NET, so the Moq 4 beta can utilise the C# 4.0 goodies like dynamic typing); last, the NMock project doesn’t seem to be as active as it once was, with the last official build released in January 2008.
As a result of this switch, I’m in more of a position to critically evaluate NMock and Moq than I was when I wrote my original post. Here’s a summary of my thoughts and experiences. Moq (which can be pronounced either as “Mock” or as “Mock-You”) is a relatively new mocking framework on the scene, with v1.0 released in December 2007. It has been designed specifically to integrate deeply with C# 3.0 and take advantage of the new language features in this version, such as implicit typing, lambda expressions and LINQ expression trees. This enables you to create mock objects, assign them behaviours and record expectations about them in a simple way; it also means that you get full Intellisense support when creating your mock objects. Moq’s other advantage is that it eschews the Record/Replay syntax favoured by Rhino Mocks, which I find quite opaque and unintuitive.
NMock, whose last build was released in January 2008 (coincidence?), was originally started for .NET 1.0, and was updated for .NET 2.0 which shipped in ~2005. It does not take advantage of the C# 3.0 language features, and so relies on a “fluent” syntax for creating stubs and recording expectations. This makes reading the expectations and stubs quite natural (the syntax is very close to English), but it is not the most natural way to program. Additionally, there is no Intellisense support for the interfaces being mocked, as the framework relies quite a bit on magic strings.
“Installing” Moq is really very simple: just download a zip file, extract it to some location, and reference Moq.dll (the only binary included) in your VS project. The fact that it’s completely contained within one binary makes it much simpler to manage the dependency on this framework in comparison with, say, NHibernate: at only 285KB, it can be added to your project without bloating your project. This all holds for NMock as well, of course.
The Moq paradigm is quite different from NMock’s. In NMock, you specify a local variable typed to your interface, and create a mock implementation (carried out by NMock via Reflection), as follows:
Object
property on the mock object to access the actual mocked object.
In NMock, you create stubs and expectations as follows:
Mockery
class). This allows a developer to get up and running with Moq more quickly than they might with NMock. Handily, Moq does support the notion of a mock factory (via the cunningly-named MockFactory
class), which provides for creating many mocks with the same settings (i.e., "strict", "partial", etc.). Creating a stub can be accomplished as follows:
repo => repo.GetById(id)
syntax is a C# lambda expression. Under the hood, this is a kind of anonymous delegate, and actually ends up creating the same IL as an anonymous delegate would. This particular lambda is equivalent to the following method:
null
, you can't use the Returns()
method as simply as you'd like: a compiler error is thrown complaining about an ambiguity between the overloads of Returns()
and Returns(Func)</code>. As such, you have to use a simple lambda expression as a parameter to the Returns()
method like so:
mockRepository.Setup(repo => repo.GetById(userId)).Returns(() => null);
The () => null
lambda is equivalent to the following method:
public User Anonymous() {
return null;
}
Other than this, however, Moq is a bit of a joy to use. Because of the use of lambdas, you get Intellisense support on your own API (e.g., when typing out repo.GetById()
), which obviously speeds things up immensely.