In this, forth (and probably final) post on the subject of Unit Tests, we’re going to dive a little deeper into the subject of mocking. We’ll discuss what the difference is between a mock, a stub, and a fake; we’ll also talk about mocking frameworks.
A Fake, Stubby, Mock
These terms are often used interchangeably, and that’s fine - but they can mean different things. There are a couple of sources (that I could find) that have defined the difference between these terms:
Mocks Aren’t Stubs - an article from 2007 by Martin Fowler.
xUnit Test Patterns - a book on Unit Testing.
Broadly, they both say the same, which is this:
A Stub is a replacement for functionality that will return a given value without actually executing any life-like code.
A Mock is similar to a stub, but allows for analysis of that behaviour - for example, you can determine whether or not the method was called, or how many times.
A Fake is a replacement for functionality that is intended to mimic the actual functionality of the code.
A Test Double is a generic term to encompass all three.
Let’s have a look at an example for each. We’ll stick with manual test doubles for now. Let’s consider one of the manual mocks that we created in the last post:
public class MockInputOutputWrapper : IInputOutputWrapper
{
private readonly string \_inputValue;
public MockInputOutputWrapper(string inputValue) =>
\_inputValue = inputValue;
public string GetInput(string prompt) => \_inputValue;
public void Output(string text) { }
}
Stub
Our first call is the stub, which is the Output method in the code above. It provides a method to call, but no functionality whatsoever.
Mock
Let’s imagine that we wanted to ascertain how many times we called Output - we may do something like this:
public class MockInputOutputWrapper : IInputOutputWrapper
{
private readonly string \_inputValue;
private int \_outputCount = 0;
public MockInputOutputWrapper(string inputValue) =>
\_inputValue = inputValue;
public string GetInput(string prompt) => \_inputValue;
public void OutputCallsMustBe(int count)
{
if (count != \_outputCount) throw new Exception("Output Calls Incorrect");
}
public void Output(string text)
{
\_outputCount++;
}
}
Now Output is a mock, rather than a stub. For this post, I won’t go to the extent of writing a mocking framework, but I think the code above illustrates the point. That is, we can ascertain that Output has been called, say, once:
[Fact]
public void Output\_ValidGuess\_CalledOnce()
{
// Arrange
var inputOutputWrapper = new MockInputOutputWrapper("12");
var randomNumberChooser = new MockRandomNumberChooser();
var sut = new Game(inputOutputWrapper, randomNumberChooser);
// Act
string result = sut.RunMethod();
// Assert
Assert.Equal("Well done, you guessed!", result);
inputOutputWrapper.OutputCallsMustBe(1);
}
Finally, we’ll discuss what a fake is.
Fake
Fakes allow for functionality to be replicated in a way that’s more conducive to the test. The stub allowed us to essentially ignore the functionality altogether; the mock allowed us to assert that, despite replacing the functionality, it had actually been invoked (or would have been); the fake allows us to substitute that functionality. A good example here is a database - in order to test the interaction with a database, you may find it necessary to actually store some data in memory. Using our example, what if we needed to ascertain that the game dealt with different random numbers; we could write this:
[Fact]
public class MockRandomNumberChooser : IRandomNumberChooser
{
private int[] \_numberList = new[] { 12, 3, 43 };
private int \_index = 0;
public int Choose() => \_numberList[\_index++];
}
Now that we understand the difference, we’ll see that it can be very academic, especially when dealing with mocking frameworks.
There’s a lot of boiler plate code here. Manually creating these classes does the job, but imagine the following scenario: you have 5 different mock classes, and you add a method to the interface IRandomNumberChooser. You now need to manually go through each of those mocks and add the functionality necessary to mock out the new function - you are very likely to not care about the new function in most of those methods, but nevertheless, you would need to go and honour the interface.
Mocking Frameworks
Mocking frameworks aim to solve this problem by creating a mechanism to mock or subclass an object. There are currently two main mocking frameworks for .Net: Nsubstitute and Moq. There’s also Microsoft Fakes.
We won’t cover all of these, and the principle behind them is broadly the same, with a slightly different implementation bias. I’ve always found NSubstitute much more intuitive, so we’ll cover that.
We’ll start by simply deleting the MockRandomNumberChooser. Now install Nsubstitute:
Install-Package NSubstitute
The next part is to simply tell NSubstitute to do the same thing that you had done using the mock class:
var randomNumberChooser = Substitute.For<IRandomNumberChooser>();
randomNumberChooser.Choose().Returns(12);
If you run the test, you’ll see absolutely no difference. Based on our discussion earlier in the post, we have created a stub, but we can create both Mocks and Fakes using the same class. If you want to create a mock, you’ll do so like this:
randomNumberChooser.Received(1).Choose();
Fakes are a little different, however, you can still replace the functionality.
References
https://www.pmichaels.net/2018/03/22/using-nsubstitute-for-partial-mocks/