Jul 20, 2010

Mocking Comparison – Part 1: The Basics

I recently gave a talk on mocking at the DDD Sydney conference called “You Look Like A Monkey and You Smell Like One Too”.  In it I not only got to call the audience various names and get mocked in return, but I also showed a number of features of mock frameworks and how they can be used.  Essentially it was a comparison of a number of mock frameworks, with a particular focus on a few of the main open source ones out there and a great new comer – specifically RhinoMocks, Moq and NSubstitute.

This is part 1 of series running through the code I had on screen and providing some thoughts on the pros and cons of each framework in the context of the scenario I’m showing.  This first part will be longer than the others simply because we have to put some ground work in place.  So, let’s stop wasting time and get started…

What Are We Testing?

All right, so in order to do any mocking we really should have an application to test.  For the purposes of this series the code is a simple class library.  It does nothing useful in the real world, but it does give us something to test.  It’s a pseudo “zoo” featuring monkeys, zoo keepers and tourists.

The IMonkey Interface

Every zoo needs a monkey, and thus we need a monkey right? Of course we do! However, because the monkeys haven’t been tested yet,  the monkeys aren’t yet on display (or at least we haven’t written the code for them yet) so all we have to interact with for now is an IMonkey interface as follows:

public interface IMonkey
{
string Name { get; set; }
bool TryAddFleas(int numberOfFleas);
int CurrentFleaCount();
void Clean();
bool IsAwake(DateTime timeOfDay);
void BananaReady(object sender, BananaEventArgs e);
event EventHandler<EventArgs> Dance;
IZooKeeper Keeper();
}

The IZooKeeper Interface and the ZooKeeper

Monkeys have Keepers, and since all staff in any organisation are just “resources” and thus completely interchangeable (grrr – don’t get me started on this kind of thinking!) we should have an IZooKeeper interface.  We are also lucky enough to actually have a standard ZooKeeper definition as well.  Here’s the code:

public interface IZooKeeper
{
event EventHandler<BananaEventArgs> OnBananaReady;
IMonkey AssignedMonkey { get; set; }
void CleanMonkey();
void FeedMonkeys();
}
public class ZooKeeper : IZooKeeper
{
public event EventHandler<BananaEventArgs> OnBananaReady;

public IMonkey AssignedMonkey { get; set; }

public void CleanMonkey()
{
if (AssignedMonkey == null) return;
if (AssignedMonkey.CurrentFleaCount() < 10) return;
if (AssignedMonkey.IsAwake(DateTime.Now))
AssignedMonkey.Clean();
}

public void FeedMonkeys()
{
if (OnBananaReady != null)
{
OnBananaReady(this, new BananaEventArgs(true));
}
}
}

public class BananaEventArgs : EventArgs
{
public BananaEventArgs(bool isRipe)
{
IsRipe = isRipe;
}

public bool IsRipe { get; private set; }
}

Tourists!

Every zoo needs tourists, and in this case we want concrete instances of tourists, not just some definition of what a tourist should be.  Our tourists are a little weird in that every tourist that comes to our zoo expects our monkeys to dance, and should that happen then they’ll take a photo.  Here’s the code:


public class Tourist
{
IMonkey monkey;

~Tourist()
{
if (monkey!= null)
monkey.Dance -= Look_ADancingMonkey;
}

public int PhotosTaken { get; private set; }

public void SeeAMonkey(IMonkey monkey)
{
if (this.monkey != monkey && this.monkey != null)
this.monkey.Dance -= Look_ADancingMonkey;

this.monkey = monkey;
monkey.Dance += Look_ADancingMonkey;
}

public void Look_ADancingMonkey(object sender, EventArgs args)
{
if (((IMonkey)sender).CurrentFleaCount() <= 100)
{
TakeAPhoto((IMonkey)sender);
}
return;
}

private void TakeAPhoto(IMonkey monkey)
{
PhotosTaken++;
Console.WriteLine(monkey.Name);
}
}

Record/Replay Is Dead

OK.  That’s done, now let’s get into it.  If you’ve used a mocking framework in previous years you may have used Record/Replay syntax.  The idea being you record the steps you want your mock to perform, then switch to replay mode, do the steps again and assert everything worked.  Here’s what Record/Replay looks like using Rhino Mocks in an XUnit test harness:


private string testName = "Spike";

[Fact]
public void Rhino_record_replay()
{
var repository = new MockRepository();
var monkey = repository.StrictMock<IMonkey>();

//In record mode at the moment
Expect.Call(monkey.Name).Return(testName);

//Now in replay mode
repository.ReplayAll();
var actual = monkey.Name;

Assert.Equal(testName, actual);
}

As you can see, we create a MockRepository object, ask the repository to give us a new mock object for a, call the method we want to mock out once, set the expected return value, then we switch to Replay mode and make the call again before finally doing our assertions.

From the small sample code you may be forgiven for thinking that the code isn’t all that bad, however the fact that you have to think about what mode you’re takes you out of the mode of thinking about what it is you’re actually meant to test, and that’s not a good thing. To make matters worse, this is a simple case.  When you get into complex cases, record/replay is downright painful and the amount of repeated code that has to happen in order to set up expectations is often overwhelming and confusing.

Oh, you’ll also notice that the sample code is using a StrictMock.  If this is what you’re doing, then stop it! StrictMocks are a great way to make your tests brittle and hard to maintain and should be avoided wherever possible.  Just search for why strict mocks are bad on your favourite search engine and you’ll no doubt find more information about it.

Use Arrange Act Assert Instead

Let’s now look at the same code using Rhino Mocks in AAA syntax mode.  In case you’re not aware of this, AAA syntax is a way of structuring the tests where you Arrange any pre-requisites for the test, Act on the class under test and then Assert that things occurred as expected.

[Fact]
public void Rhino_arrange_act_assert()
{
//Arrange
var monkey = MockRepository.GenerateMock<IMonkey>();
monkey.Stub(m => m.Name).Return(testName);

//Act
var actual = monkey.Name;

//Assert
Assert.Equal(testName, actual);
}

As you can see, the code is simpler, structured more cleanly and is also easier to read.  In large test libraries this makes things much more maintainable, which is a good thing.

The Moq Version

So far the code has used the Rhino Mocks framework.  Another very popular framework is Moq.  Here’s what the same test in Moq looks like:

[Fact]
public void Moq_arrange_act_assert()
{
var monkey = new Mock<IMonkey>();
monkey.Setup(m => m.Name).Returns(testName);

var actual = monkey.Object.Name;

Assert.Equal(testName, actual);
}

Moq became popular when it was released because no other test framework could do what it did in terms of setting up expectations via lambdas and providing such an easy way of performing AAA style tests.

Over time the other frameworks have caught up, and for me personally, the fact that Moq has a distinct delineation between the mock and the object being mocked (i.e. the monkey.Object code) adds clutter to the test code that I don’t like.  Others like that clarity, but I personally find it just gets in the way.

On the other hand, mock object creation is far less verbose, which is a good thing.

NSubstitute

Finally, the new kid on the block.  NSubstitute’s code looks like the following:

[Fact]
public void Nsubstitute_arrange_act_assert()
{
var monkey = Substitute.For<IMonkey>();
monkey.Name.Returns(testName);

var actual = monkey.Name;

Assert.Equal(testName, actual);
}

What you see is that the code is much terser than Rhino and Moq.  A mock is created as a “substitute for” a IMonkey and we don’t need to use lambdas to set return values for a mocked property, greatly improving readability of the test code and making test code feel more expressive.

My preference of the three for the basic syntax and coding? NSubstitute.

 

Other posts in this series:

5 comments:

  1. Thanks for posting this and thanks for your talk at ReadifyReadifyReadify! ;)

    Cheers,
    Stonie.

    ReplyDelete
  2. Moq now permits creating stubs without the "mock.Object" distinction.

    See http://www.truewill.net/myblog/index.php/2011/04/20/moq_v4_functional_specifications

    ReplyDelete
  3. This series of comparisons of the 3 mock frameworks by purpose is extremely well done and instructive. Thanks for taking the time to explain and include thorough examples.

    ReplyDelete
  4. wow. classified as an awesome walkthrough. big thanks for the tips and detailed explanation.

    ReplyDelete
  5. Thanks for letting me know about NSubstitute! If you haven't before, check out Should for even nicer assertions: http://should.codeplex.com/ (especially the fluent syntax)

    ReplyDelete