DEV Community

Cover image for Moq vs NSubstitute: syntax cheat sheet
Davide Bellone
Davide Bellone

Posted on • Originally published at code4it.dev

Moq vs NSubstitute: syntax cheat sheet

When writing Unit Tests, you usually want to mock dependencies. In this way, you can define the behavior of those dependencies, and have full control of the system under test.

For .NET applications, two of the most used mocking libraries are Moq and NSubstitute. They allow you to create and customize the behavior of the services injected into your classes. Even though they have similar functionalities, their syntax is slightly different.

In this article, we will learn how the two libraries implement the most used functionalities; in this way, you can easily move from one to another if needed.

A real-ish example

As usual, let's use a real example.

For this article, I've created a dummy class, StringsWorker, that does nothing but call another service, IStringUtility.

public class StringsWorker
{
    private readonly IStringUtility _stringUtility;

    public StringsWorker(IStringUtility stringUtility)
        => _stringUtility = stringUtility;

    public string[] TransformArray(string[] items)
        => _stringUtility.TransformAll(items);

    public string[] TransformSingleItems(string[] items)
        => items.Select(i => _stringUtility.Transform(i)).ToArray();

    public string TransformString(string originalString)
        => _stringUtility.Transform(originalString);
}
Enter fullscreen mode Exit fullscreen mode

To test the StringsWorker class, we will mock its only dependency, IStringUtility. This means that we won't use a concrete class that implements IStringUtility, but rather we will use Moq and NSubstitute to mock it, defining its behavior and simulating real method calls.

Of course, to use the two libraries, you have to install them in each tests project.

How to define mocked dependencies

The first thing to do is to instantiate a new mock.

With Moq, you create a new instance of Mock<IStringUtility>, and then inject its Object property into the StringsWorker constructor:

private Mock<IStringUtility> moqMock;
private StringsWorker sut;

public MoqTests()
{
    moqMock = new Mock<IStringUtility>();
    sut = new StringsWorker(moqMock.Object);
}
Enter fullscreen mode Exit fullscreen mode

With NSubstitute, instead, you declare it with Substitute.For<IStringUtility>() - which returns an IStringUtility, not wrapped in any class - and then you inject it into the StringsWorker constructor:

private IStringUtility nSubsMock;
private StringsWorker sut;

public NSubstituteTests()
{
    nSubsMock = Substitute.For<IStringUtility>();
    sut = new StringsWorker(nSubsMock);
}
Enter fullscreen mode Exit fullscreen mode

Now we can customize moqMock and nSubsMock to add behaviors and verify the calls to those dependencies.

Define method result for a specific input value: the Return() method

Say that we want to customize our dependency so that, every time we pass "ciao" as a parameter to the Transform method, it returns "hello".

With Moq we use a combination of Setup and Returns.

moqMock.Setup(_ => _.Transform("ciao")).Returns("hello");
Enter fullscreen mode Exit fullscreen mode

With NSubstitute we don't use Setup, but we directly call Returns.

nSubsMock.Transform("ciao").Returns("hello");
Enter fullscreen mode Exit fullscreen mode

Define method result regardless of the input value: It.IsAny() vs Arg.Any()

Now we don't care about the actual value passed to the Transform method: we want that, regardless of its value, the method always returns "hello".

With Moq, we use It.IsAny<T>() and specify the type of T:

moqMock.Setup(_ => _.Transform(It.IsAny<string>())).Returns("hello");
Enter fullscreen mode Exit fullscreen mode

With NSubstitute, we use Arg.Any<T>():

nSubsMock.Transform(Arg.Any<string>()).Returns("hello");
Enter fullscreen mode Exit fullscreen mode

Define method result based on a filter on the input: It.Is() vs Arg.Is()

Say that we want to return a specific result only when a condition on the input parameter is met.

For example, every time we pass a string that starts with "IT" to the Transform method, it must return "ciao".

With Moq, we use It.Is<T>(func) and we pass an expression as an input.

moqMock.Setup(_ => _.Transform(It.Is<string>(s => s.StartsWith("IT")))).Returns("ciao");
Enter fullscreen mode Exit fullscreen mode

Similarly, with NSubstitute, we use Arg.Is<T>(func).

nSubsMock.Transform(Arg.Is<string>(s => s.StartsWith("IT"))).Returns("ciao");
Enter fullscreen mode Exit fullscreen mode

Small trivia: for NSubstitute, the filter is of type Expression<Predicate<T>>, while for Moq it is of type Expression<Func<TValue, bool>>: don't worry, you can write them in the same way!

Throwing exceptions

Since you should test not only happy paths, but even those where an error occurs, you should write tests in which the injected service throws an exception, and verify that that exception is handled correctly.

With both libraries, you can throw a generic exception by specifying its type:

//Moq
moqMock.Setup(_ => _.TransformAll(null)).Throws<ArgumentException>();

//NSubstitute
nSubsMock.TransformAll(null).Throws<ArgumentException>();
Enter fullscreen mode Exit fullscreen mode

You can also throw a specific exception instance - maybe because you want to add an error message:

var myException = new ArgumentException("My message");

//Moq
moqMock.Setup(_ => _.TransformAll(null)).Throws(myException);

//NSubstitute
nSubsMock.TransformAll(null).Throws(myException);
Enter fullscreen mode Exit fullscreen mode

If you don't want to handle that exception, but you want to propagate it up, you can verify it in this way:

Assert.Throws<ArgumentException>(() => sut.TransformArray(null));
Enter fullscreen mode Exit fullscreen mode

Verify received calls: Verify() vs Received()

Sometimes, to understand if the code follows the execution paths as expected, you might want to verify that a method has been called with some parameters.

To verify it, you can use the Verify method on Moq.

moqMock.Verify(_ => _.Transform("hello"));
Enter fullscreen mode Exit fullscreen mode

Or, if you use NSubstitute, you can use the Received method.

nSubsMock.Received().Transform("hello");

Enter fullscreen mode Exit fullscreen mode

Similar as we've seen before, you can use It.IsAny, It.Is, Arg.Any and Arg.Is to verify some properties of the parameters passed as input.

Verify the exact count of received calls

Other times, you might want to verify that a method has been called exactly N times.

With Moq, you can add a parameter to the Verify method:

sut.TransformSingleItems(new string[] { "a", "b", "c" });

moqMock.Verify(_ => _.Transform(It.IsAny<string>()), Times.Exactly(3));
Enter fullscreen mode Exit fullscreen mode

Note that you can specify different values for that parameter, like Time.Exactly, Times.Never, Times.Once, Times.AtLeast, and so on.

With NSubstitute, on the contrary, you can only specify a defined value, added as a parameter to the Received method.

sut.TransformSingleItems(new string[] { "a", "b", "c" });

nSubsMock.Received(3).Transform(Arg.Any<string>());
Enter fullscreen mode Exit fullscreen mode

Reset received calls

As you remember, the mocked dependencies have been instantiated within the constructor, so every test method uses the same instance. This may cause some troubles, especially when checking how many calls the dependencies have received (because the count of received calls accumulates for every test method run before). Therefore, we need to reset the count of the received calls.

In NUnit, you can define a method that will run before any test method - but only if decorated with the SetUp attribute:

[SetUp]
public void Setup()
{
  // reset count
}
Enter fullscreen mode Exit fullscreen mode

Here we can reset the number of the recorded method invocations on the dependencies and make sure that our test methods use always clean instances.

With Moq, you can use Invocations.Clear():

[SetUp]
public void Setup()
{
    moqMock.Invocations.Clear();
}
Enter fullscreen mode Exit fullscreen mode

While, with NSubstitute, you can use ClearReceivedCalls():

[SetUp]
public void Setup()
{
    nSubsMock.ClearReceivedCalls();
}
Enter fullscreen mode Exit fullscreen mode

Further reading

As always, the best way to learn what a library can do is head to its documentation. So, here you can find the links to Moq and NSubstitute docs.

๐Ÿ”— Moq documentation | GitHub

๐Ÿ”— NSubstitute documentation | NSubstitute

If you already use Moq but you are having some troubles testing and configuring IHttpClientFactory instances, I got you covered:

๐Ÿ”— How to test HttpClientFactory with Moq | Code4IT

Finally, if you want to see the complete code of this article, you can find it on GitHub; I've written the exact same tests with both libraries so that you can compare them more easily.

๐Ÿ”— GitHub repository for the code used in this article | GitHub

Conclusion

In this article, we've seen how Moq and NSubstitute allow us to perform some basic operations when writing unit tests with C#. They are similar, but each one of them has a specific set of functionalities that are missing on the other library - or, at least, that I don't know if they exist in both.

Which library do you use, Moq or NSubstitute? Or maybe, another one?

Happy coding!
๐Ÿง

Top comments (1)

Collapse
 
taepunphu profile image
Kiattisak Phanphu

Thank you