Mocking in .NET – Moving From NMock to Moq

By | July 11, 2010

Recently I came across NMock3, which improved upon NMock2 by providing for strongly-typed expectations on any mock objects you might create. I stumbled across this while reading this post comparing different mocking frameworks. In this same post however, one of the original contributors to NMock2 gave a compelling reason why he switched to Moq. This post is a bare bones introduction to the main difference between NMock and Moq that, from my perspective, makes it a no-brainer to switch, and demonstrates how to augment your test app to include both so you can easily migrate from one to the other over time.

The NMock Way

We’ll be starting with the code that we spun up in my prior post regarding moving from NMock2 to NMock3. The NMock3 version of the test that we’ll be using to compare the frameworks is below.

[Test]
public void SomeBizCountIsLazyLoadedTest2()
{
    MockFactory mf = new MockFactory();

    Mock<IBizRepo> mockRepo = mf.CreateMock<IBizRepo>();
    mockRepo.Expects.One.Method(m => m.GetSomeCount(""))
        .With("bizobjectname").Will(Return.Value(42));

    BizObject b = new BizObject("bizobjectname", mockRepo.MockObject);
    Assert.That(b.SomeBizCount, Is.EqualTo(42));

    mf.VerifyAllExpectationsHaveBeenMet();
}

The details behind the implementation and the classes under test were detailed in my post cited above; suffice to say that we are checking for a return value of 42 on the SomeBizCount method, and that we are also checking that the GetSomeCount method is called on our mock repository with an input parameter of “bizobjectname”.

Bring in the Moqs

To compare NMock to Moq, we first have to add Moq support to our test library. The first step is to download the latest version of the Moq binaries from here. Once we’ve extracted the downloaded file, we pull out the 3.5 framework version of the Moq libraries, which is just Moq.dll, and add it to our ReferencedDLLs folder.

addingMoqDll

Next step is to add a reference to the Moq.dll from our BizLayerTests project. One thing to note is that there are some naming conflicts between the NMock2 namespace that NMock3 provides (yes, you read that correctly) and the Moq namespace. So if you’re going to have both mocking frameworks in the same class file, you’ll have to fully qualify them. Either way, once the reference has been added, we’re ready to rock and roll.

The Moq Way

The same test above can be written using Moq as pictured below.

[Test]
public void SomeBizCountIsLazyLoadedTest3()
{
    Mock<IBizRepo> mockRepo = new Mock<IBizRepo>();
    mockRepo.Setup(m => m.GetSomeCount("bizobjectname")).Returns(42);

    BizObject b = new BizObject("bizobjectname", mockRepo.Object);
    Assert.That(b.SomeBizCount, Is.EqualTo(42));
    mockRepo.Verify(m => m.GetSomeCount("bizobjectname"), Times.Exactly(1));
}

It becomes readily apparent what the advantage of Moq’s approach is, at least from a readability perspective. Whereas in the NMock version we had a call to the VerifyAllExpectationsHaveBeenMet method, coupled with details as to exactly what expectations are being set in the arrange portion of our test, in the Moq version we have a more precise statement of what we expect in the assert portion of our test. The arrange portion of our test, where we “arrange” the objects that we want to test, no longer has a sprinkle of assertion on it. The test flows a bit better, and in keeping with my appreciation of fluent interfaces, simply reads better.

Simply put, at the beginning of the test I’m only stating what I expect to get from my mocked method call. At the end is where I assert how many times I expected my mocked method call to be invoked. Splitting hairs? Maybe; but it sits better in my programming gut, and I’ve come to trust that.

Going Forward

I’ll be presenting Moq to my team in the coming week so as to solicit feedback regarding my perceived advantages. I prefer to manage by consensus as opposed to fiat, so we’ll see what their reaction is to the slightly different syntax and style. Hopefully, they agree, and we can begin to phase it into our new development.