Moq : Mocking Made Simple

Unit testing is a very important part of the development process. With in the scope of testing, being able to isolate the code being tested from external dependencies (ex: REST service, 3rd party library, etc), is key to ensuring accurate results. A unit test shouldn't fail because of an environmental factor like the network being offline. With that in mind, creating mocked (aka; FAKE) instances of these dependencies is required to ensure reliable testing. There are a few mocking frameworks available for .NET projects, but the one I would recommend everyone to use is Moq.

What is Moq?

Moq (pronounced "Mock" or "Mock You"), is a very powerful, but lightweight and unobtrusive, mocking framework build for use with .NET CLR code. It utilizes many of the language features in C# to provide strongly typed mocks, without having the users to learn unnatural usage patterns.

Installing Moq

Moq's main website is http://code.google.com/p/moq/, and the library can be downloaded from there. The library can also be installed as a NuGet package either from Visual Studio 2010 or http://nuget.org/.

Creating your first Mock

You can download a copy of the project setup I am going to use (moqintropart1-start.zip).

Note: The only detail that is important in the DLL project is that the interface (IAwesomeService) is to be assumed as an interface for an external dependency (such as a web service). The class (EpicClass) is the class we are going to test on, however it has a dependency on the AwesomeService.

In the Tests.cs file, you should see a class that looks like this:

[TestClass]
public class Tests
{
    [TestMethod]
    public void EpicTest()
    {
    }
}

The EpicTests method is where we are going to run our test against the EpicClass. Obviously, we will need to create an instance of the EpicClass to test, however it requires an instance of IAwesomeService passed into it. To create an instance of that interface, we are going to use a mock.

var awesomeMock = new Mock<IAwesomeService>();
var epic = new EpicClass(awesomeMock.Object);

That code block creates a Mock of the IAwesomeService and then passes an instance of the interface to the constructor of the EpicClass. The Mock.Object property returns an instance of T that the Mock has created.

We can now execute methods on the the EpicClass instance and setup the assertions for the test.

int one = epic.GetNextNumber();
int two = epic.GetNextNumber();
string bar = epic.Foo();


Assert.AreEqual(1, one);
Assert.AreEqual(2, two);
Assert.AreEqual("bar", bar);

This code will compile and run, however the test will fail, since the assertions will state that the return values from the methods from the EpicClass instance are incorrect from what we were expecting. This is because, while we have created a mock of the IAwsomeService, we haven't told it what to do when its members are called. The default behavior of mocks created by Moq, is to return the default value of the type for any member. We have to setup the expectations of what we are going to call on the mock object.

Setting up Expectations

Setting and configuring expectations with Moq is very easy. Moq takes advantage of many C# language features such as Lambda expressions to provide strongly typed APIs for configuring member expectations on mocked objects.

First, we will configure the call to IAwesomeService.AddOne(int). These setups should be placed just after the mock was declared, and the actual code looks like the following:

awesomeMock.Setup(m => m.AddOne(It.IsAny<int>()))
            .Returns<int>((input) => input + 1);

There are a few things going on here. First we are telling Moq we want to configure the expectation for AddOne(int). This is done with the parameter to the Setup method, which takes the expression: m => m.AddOne(It.IsAny()), as the parameter. The AddOne method has a parameter of its own, and that's were the placeholder of It.IsAny() comes into play. Using that as the placeholder for the integer parameter, tells Moq to use this expectation for any calls to AddOne(int).

The second part involves describing the return value from the call to AddOne(int). The general idea of the AddOne method is that it adds one to the value that was passed in, so with Moq we can get the value of the input parameter by using a Type argument on the Returns method. All that is required now is to provide an expression that returns an integer.

That is all that is required for configuring an expectation on the mock object. If you re-run the test, the first two assertions will pass, but not the third. The expectation for this call should look like this

awesomeMock.Setup(m => m.GetMatchingString("foo"))
            .Returns("bar");

This expectation is simple compared to the previous one. This expectation will only be run when the input parameter is exactly "foo", and will return the result of "bar". There will be a detailed post later about input criteria filters.

With the second expectation configured, complete unit test method should look like this:

    [TestMethod]
    public void EpicTest()
    {
        // setup
        var awesomeMock = new Mock<IAwesomeService>();
        awesomeMock.Setup(m => m.AddOne(It.IsAny<int>()))
            .Returns<int>((input) => input + 1);
        awesomeMock.Setup(m => m.GetMatchingString("foo"))
            .Returns("bar");

        var epic = new EpicClass(awesomeMock.Object);

        // execute
        int one = epic.GetNextNumber();
        int two = epic.GetNextNumber();
        string bar = epic.Foo();

        // verify
        Assert.AreEqual(1, one);
        Assert.AreEqual(2, two);
        Assert.AreEqual("bar", bar);
    }

This test code will pass when run in the Visual Studio unit test framework, provided you downloaded the solution zip file mentioned above.

I hope this post has shown you how easy it is to get a mock setup with Moq.

comments powered by Disqus