Moq vs NSubstitute vs FakeItEasy - Which one to choose?
Writing real unit tests or not. We as software developers seem to switch between thinking it's the best idea ever to everything should just be integrated tested. I too changed my mind multiple times around this subject over the years. No matter where I have been on that roller coaster, I have always needed a mocking framework. In this post, I'll introduce you to mocking and to the three major options out there.
If you are not familiar with mocking, let's start with a quick example that is used throughout this article to explain the differences between the three mocking frameworks. This is in no way a complete introduction to mocks in any way, but basic knowledge of the subject should be sufficient to understand the rest of the content.
If you already know what unit tests and mock objects are, feel free to jump directly to Mocking Frameworks.
Let's say we want to create a class able to tell if a movie is good or not. The interface could look similar to this:
public interface IMovieSuggestion
{
bool IsGoodMovie(string title);
}
The IsGoodMovie
method accepts a title and returns a boolean indicating if the movie is good or not. Yeah yeah, I know, a title isn't sufficient to identify a movie. Play along, ok? Here's the unfinished class:
public class MovieSuggestion : IMovieSuggestion
{
public bool IsGoodMovie(string title)
{
var score = ...; // Fetch score from IMDb
return score >= 8;
}
}
In the first line of the IsGoodMovie
method fetch the IMDb score and then return true if the score is 8 or above. If we want to test this using a real unit test, we need to test small parts not dependent on IMDb being online or any network connection present. In this example, we want to test the algorithm determining if a movie is good or not and not the communication with IMDb. Furthermore, we want to be in control of what score a movie title is given when testing this code. Let's say we use The Shawshank Redemption as input for our integration test and the score drops below 8 (will never happen, but still). Our test suddenly starts failing from circumstances that we are not in control of.
You already know the answer: dependency injection:
public interface IMovieScore
{
double Score(string title);
}
The new IMovieScore
can fetch a score from a movie title. We use constructor injection to extract the IMDb communication from the MovieSuggestion
class:
public class MovieSuggestion : IMovieSuggestion
{
private readonly IMovieScore movieScore;
public MovieSuggestion(IMovieScore movieScore)
{
this.movieScore = movieScore;
}
public bool IsGoodMovie(string title)
{
var score = movieScore.Score(title);
return score >= 8;
}
}
We can now write a test and inject a test implementation of IMovieScore
that returns a hardcoded value:
class MovieSuggestionTest_Manual
{
[TestCase(false, 0)]
[TestCase(false, 0)]
[TestCase(false, 7.99)]
[TestCase(true, 8)]
[TestCase(true, 10)]
public void CanSuggest(bool expected, double score)
{
// Arrange
var movieScore = new MovieScoreStub(score);
var movieSuggestion = new MovieSuggestion(movieScore);
var title = Guid.NewGuid().ToString();
// Act
var isGood = movieSuggestion.IsGoodMovie(title);
// Assert
Assert.That(isGood, Is.EqualTo(expected));
}
private class MovieScoreStub : IMovieScore
{
private double score;
public MovieScoreStub(double score)
{
this.score = score;
}
public double Score(string title)
{
return score;
}
}
}
I have included a couple of score inputs and verify the result of IsMovieGood
using NUnit and a test implementation of IMovieScore
named MovieScoreStub
. This implementation is only created for the test and to make sure that we don't need IMDb to be online and we now have control of the score returned for a movie title.
As shown in the example, we already have a lot of code written for the test exclusively. Consider some more advanced code and you can imagine how the complexity grows. Say hello to mock objects.
Mocking frameworks
Mocking frameworks were born to avoid creating homemade stubs like in the previous example. They have a lot of options for both setting up complex call trees as well as verify that methods and properties on dependencies were in fact called.
There are a lot of options available for .NET developers like us. I started using NMock back when SourceForge was the go-to place to download DLL files. Then switched to RhinoMocks which introduced a brand new way of setting up mocks that felt more C#'ish (NMock was a port of jMock for Java).
With NMock and RhinoMocks last updated in 2013 and 2014, there seem to be three good options left: Moq, NSubstitute, and FakeItEasy. I have used all of them over the years and experienced some of the good and bad of each framework. In the rest of this post is split into a section per framework where I'll show you how to implement the test above with each mocking framework.
Moq
When Moq came out, I was pretty quick to jump aboard. While RhinoMocks was a nice framework, Moq just seemed simpler and had a simpler syntax. In fact, Moq is used to test most of the code on elmah.io. Let's dig in.
Moq has, as the only one of the three, a dedicated Mock
class to represent a mock. You use generics to specify the type to mock:
var movieScore = new Mock<IMovieScore>();
The Mock
class has methods for setting up expectations:
movieScore.Setup(ms => ms.Score(It.IsAny<string>())).Returns(score);
The Setup
and Returns
methods are used to set up any method calls on the mocks and what they should return. Be aware that a Setup
is not a requirement for the specified method to be called, simply a hint.
The setup verification of a method being called with a specific parameter, use the Verify
method:
movieScore.Verify(ms => ms.Score(title));
Implementing the test from the example with Moq could look something like this:
[TestCase(false, 0)]
[TestCase(false, 0)]
[TestCase(false, 7.99)]
[TestCase(true, 8)]
[TestCase(true, 10)]
public void CanSuggest(bool expected, double score)
{
// Arrange
var movieScore = new Mock<IMovieScore>();
movieScore.Setup(ms => ms.Score(It.IsAny<string>())).Returns(score);
var movieSuggestion = new MovieSuggestion(movieScore.Object);
var title = Guid.NewGuid().ToString();
// Act
var isGood = movieSuggestion.IsGoodMovie(title);
// Assert
Assert.That(isGood, Is.EqualTo(expected));
movieScore.Verify(ms => ms.Score(title));
}
I already explained the Setup
, Returns
, and Verify
methods. One additional note here is about using the mock object. Notice the line where I create the new MovieSuggestion
class. The constructor requires an IMovieScore
object. Since the movieScore
object is of type Mock
, we need to call .Object
. This syntax is the source of much debate and you probably either like being explicit about this being a mock or hate it. To be honest, I always saw it as a downside compared to RhinoMocks, but I chose to live with it in exchange for all of the other great features of Moq.
Advantages
- Widely adopted
- Explicit mocks (if you prefer that)
Disadvantages
.Object
syntax (if you prefer a solution without a dedicatedMock
class)- Setup and verification use lambdas which make the code more complex to read
- Some people are frustrated by this (I totally understand why he doesn't want to work for free, though): https://www.reddit.com/r/dotnet/comments/15ljdcc/does_moq_in_its_latest_version_extract_and_send/
NSubstitute
NSubstute has been around as long as Moq. I have looked at it a couple of times over the years. To be honest, I don't remember exactly why I didn't see the benefits until now. Maybe the API changed a lot over the years. After rediscovering NSubstitute, we have used it a lot on elmah.io. Let's take a look at some code.
NSubstitute doesn't have a dedicated class to represent a mock like Moq. In that way, it feels a bit more like RhinoMocks which had a static class to generate mocks. In NSubstitute you use the Substitute
class to generate mock objects:
var movieScore = Substitute.For<IMovieScore>();
Since For
returns an implementation of the IMovieScore
interface, setting up method calls and their return values simply requires you to call the methods directly on the mocked implementation:
movieScore.Score(Arg.Any<string>()).Returns(score);
The Arg.Any
method works exactly the same way as It.IsAny
method in Moq, but the line is definitely more condensed and readable. NSubstitute does this (as the only of the three) by adding some clever extension methods on the mocked object.
To verify that a method was called on the mock, you use a similar syntax but with an included Received
in front of the method you expect to be called:
movieScore.Received().Score(title);
Again, no lambdas, simply call the method you expect the code to call with the parameter expected.
Implementing the test above with NSubstitute could look like this:
[TestCase(false, 0)]
[TestCase(false, 0)]
[TestCase(false, 7.99)]
[TestCase(true, 8)]
[TestCase(true, 10)]
public void CanSuggest(bool expected, double score)
{
// Arrange
var movieScore = Substitute.For<IMovieScore>();
movieScore.Score(Arg.Any<string>()).Returns(score);
var movieSuggestion = new MovieSuggestion(movieScore);
var title = Guid.NewGuid().ToString();
// Act
var isGood = movieSuggestion.IsGoodMovie(title);
// Assert
Assert.That(isGood, Is.EqualTo(expected));
movieScore.Received().Score(title);
}
The code is pretty self-explanatory and doesn't require you to use .Object
like the Moq one.
Advantages
- The most simple syntax of the three
- Good documentation
Disadvantages
- Static state can cause problems with multiple tests (I've only read about this, not experienced it - yet)
FakeItEasy
FakeItEasy is yet another mocking framework for .NET. It was released at around the same time as the other two frameworks but never got the same traction as Moq and NSubstitute. It still has some interesting concepts and I know people that prefer it over the two others. The API is sort of a hybrid between the two other frameworks. The more choices the better. Let's look at some code.
Creating mocks is dine pretty much like NSubstibute using a static factory:
var movieScore = A.Fake<IMovieScore>();
The Fake
method generates the mock object as a direct implementation of the interface (or class). Setting up method invocations and return objects look similar to how it is done with Moq:
A.CallTo(() => movieScore.Score(A<string>.Ignored)).Returns(score);
The CallTo
method accepts a lambda with the call to the expected method and the Returns
method works as in the other two frameworks. Setting up a method was called verification looks very similar:
A.CallTo(() => movieScore.Score(title)).MustHaveHappened();
The complete test with FakeItEasy of the movie suggester could look like this:
[TestCase(false, 0)]
[TestCase(false, 0)]
[TestCase(false, 7.99)]
[TestCase(true, 8)]
[TestCase(true, 10)]
public void CanSuggest(bool expected, double score)
{
// Arrange
var movieScore = A.Fake<IMovieScore>();
A.CallTo(() => movieScore.Score(A<string>.Ignored)).Returns(score);
var movieSuggestion = new MovieSuggestion(movieScore);
var title = Guid.NewGuid().ToString();
// Act
var isGood = movieSuggestion.IsGoodMovie(title);
// Assert
Assert.That(isGood, Is.EqualTo(expected));
A.CallTo(() => movieScore.Score(title)).MustHaveHappened();
}
The full code shows my point of being a hybrid pretty well. FakeItEasy uses lambdas to set up expectations and verifications like Moq but no dedicated mock object like NSubstitute.
Advantages
- A mock is the real object and doesn't require
.Object
- Consistent setup and verification
Disadvantages
- Not the same traction as the other two frameworks
Conclusion
I hope that you learned something and want to try out these mocking frameworks. It's hard to point at a winner. I have been using Moq for years but recently switched to NSubstitute. I really like the use of extension methods, which produce some very clean and readable code. With that said, I'm sure that choosing any of the three would improve the way you write tests.
elmah.io: Error logging and Uptime Monitoring for your web apps
This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.
See how we can help you monitor your website for crashes Monitor your website