Moq vs NSubstitute vs FakeItEasy - Which one to choose?

TOC

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 around 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 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 injecting 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 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 goto place to download DLL files. Then switched to RhinoMocks that 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 goods and bads of each framework. In the rest of this post is split into a section per framework were 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 set up 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 around 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 dedicated Mock class)
  • Setup and verification uses lambdas which makes the code more complex to read

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 saw 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 require 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 accept a lambda with the call to the expected method and the Returns method work 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.

Features steps
We monitor your websites

We monitor your websites

We monitor your websites for crashes and availability. This helps you get an overview of the quality of your applications and to spot trends in your releases.

We notify you

We notify you

We notify you when errors starts happening using Slack, Microsoft Teams, mail or other forms of communication to help you react to errors before your users do.

We help you fix bugs

We help you fix bugs

We help you fix bugs quickly by combining error diagnostic information with innovative quick fixes and answers from Stack Overflow and social media.

See how we can help you monitor your website for crashes Monitor your website