Mock Object Vocabulary

Everyone who has written unit tests has worked with “mocks” or “mock objects”. I wrote it on purpose in parenthesis because we usually talk about “mocks” when we should talk about test doubles. The term “test double” was originally introduced by Gerard Meszaros in his book xUnit Test Patterns (2007). We think that “mock = test double” and because of that I also often talk about “mocks”. But if we are accurate we should use words stub, mock, fake, dummy, etc.

A test double is an object that can stand in for a real object in a test, similar to how a stunt double stands in for an actor in a movie.

Andrew Trenk

Test Double is a generic term for any case where you replace a production object for testing purposes.

Martin Fowler

Nowadays I’ve been trying to start be more accurate with the word “mock” in my code and to use proper word for different “mock objects”. But it is not always so easy. For example, I can’t always figure out the difference between fake, stub and dummy. By writing this blog post I will also try to learn differences between them and learn to use the right word for different test doubles in my tests.

Probably one reason we are using word mock instead of test double is in the names of popular mocking frameworks: Moq, Mockito, and jMock to mention few of them. It is quite natural to start talking about mocks when there is a class named Mock for example in Moq NuGet:

var myMock = new Mock<IMyInterface>().Object;

I will now introduce a different test doubles. All code samples are written in C# and uses Moq NuGet and its Mock class.

Dummy

Martin Fowler describes dummy perfectly: “Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.”

One case where a dummy object is needed is as a required parameter. For example, if a parameter can’t be null, then we create a dummy object and pass it as a parameter.

var loggerDummy = new Mock<ILogger>().Object;
var sut = new MyObject(loggerDummy);
// MyObject(null) can't be used because logger is required parameter
// and has null check in the code.
// Thus have to give dummy/null object instead.

Notice that if we use dummy objects, it is not a dummy object, it is some else test double then (probably stub or fake). We can think a dummy object is the same as a null object.

Stub

A stub has no logic, and only returns what you tell it to return.

Andrew Trenk

We can think stub as an object whose return values etc. are static/const values.

var carStub = new Mock<ICar>();
carStub.Setup(car => car.GetSpeed()).Returns("100 km/h");

// Speed will be always "100 km/h". There isn't any special logic.
var speed = carStub.Object.GetSpeed();

Fake

Fake is a close relative to stub. They both implement some logic of the parent class but in a different way. Fake has some logic; it doesn’t just return static values as stub does.

FakeStub
Returns dynamic values and has some logic.Returns static values and doesn’t have any logic.
Differences between fakes and stubs.

Fakes aren’t trivial to create with mocking frameworks, and according to Andrew Trenk, fakes don’t use a mocking framework. I agree with him. Here I’ve written PersonFake class instead:

public interface IPerson
{
  string Greeting();
}

public class PersonFake : IPerson
{
  public string Name { get; set; }
  public string Greeting()
  {
    // Fake has at least some logic.
    if (Name == null) return "Hello nobody!";
    if (Name == "Lassi") return "Hello blogger!";
    return "Hello!";
  }
}

As we can see there is some logic in PersonFake‘s Greeting method. It depends on the test method how we would write a fake class.

Here is an example of a IPerson stub where Greeting method just returns “Hello” compared to fake that returned different values according to name.

public class PersonStub : IPerson
{
  public string Greeting()
  {
    // Stub doesn't have logic!
    return "Hello!";
  }
}

Mock

As we saw with dummy, stub, and fake, I’d say usually when we say we are using mock, actually, we should say we are using dummy, stub or fake. So what is a mock object? How does it differ from previous ones? A mock object is used in an assertion step of the test.

// arrange
var loggerMock = new Mock<ILogger>();
var sut = new MyObject(loggerMock.Object);

// act
sut.Execute();

// assert
loggerMock.Verify(
  logger => logger.LogInfo("execution started"),
  Times.Once);

As we can see, compared to dummy, stub, and fake, a mock object is used in the assert step to verify that for example some method was called (in our case LogInfo method with “execution started” parameter). The above example is simple but it can verify more specifically also, depending on the test.

If our test double has some logic and we also use it in the assert step, is it fake or mock? I would name it as a mock because in my opinion “fake is smaller than mock”.

A mock object is a fake object in the system that decides whether the unit test has passed or failed. It does so by verifying whether the object under test called the fake object as expected. There’s usually no more than one mock per test.

Roy Osherove

Spy (Deprecated?)

Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.

Martin Fowler

Martin Fowler and Gerard Meszaros mentioned spies in 2006. But it seems that the term “spy” isn’t used much anymore and mostly we use the term “mock” to mean the same. When I searched for blog posts about test doubles, many of them ignored spies and didn’t even mention them.

As I look above definition, for me it is a mock object. Maybe because usually mocking frameworks record that information. At least Moq NuGet tells how many times some method was called. Probably some mocking frameworks use the term spy instead of mock. So we should at least know what spy means when we see code that uses it instead of more familiar mock.

Conclusion

Test doubles make automated testing much better. As a unit test enthusiast I also like test doubles and use Moq NuGet a lot. But I’ve used term mock too widely. I have named my variable as a fake even if it was a mock. Or as a mock even if I didn’t use it in assert step.

It will make tests clearer if we use more detailed names I demonstrated here. From now on, I will write dummies, stubs, fakes and mocks and name them accordingly, and not always use the term “mock”.

Sources

Leave a comment