Date:

Share:

Moq vs NSubstitute: syntax cheat sheet

Related Articles

When writing unit tests, you usually want to make fun of the hang. This way, you can define the behavior of these dependencies, and gain complete control over the system under test.

For .NET applications, two of the most common ridicule directories are Moq and N replaces. They allow you to create and customize the behavior of the injected services to your lessons. Although they have similar functions, their syntax is slightly different.

In this article, we will learn how the two libraries implement the most common functions; This way, you can easily move from one to the other if necessary.

A real example

As usual, let’s use a real example.

For this article, I created a dummy class, StringsWorker, It 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);

To check the StringsWorker In class, ridiculous to hang his unit, IStringUtility. This means we will not use a concrete implementing department IStringUtility, But we will use Moq and NSubstitute to mock him, define his behavior and simulate calls to true method.

Of course, to use both libraries, you must install them in each testing project.

How to set dependency for mockery

The first thing to do is create a new look.

With MoqYou’re creating a new show of Mock<IStringUtility>, And then inject it Object Property into StringsWorker constructor:

private Mock<IStringUtility> moqMock;
private StringsWorker sut;

public MoqTests()

    moqMock = new Mock<IStringUtility>();
    sut = new StringsWorker(moqMock.Object);

With N replaces, Instead, you declare it with Substitute.For<IStringUtility>() – which returns an IStringUtility, Not wrapped in any class – then you inject it into StringsWorker constructor:

private IStringUtility nSubsMock;
private StringsWorker sut;

public NSubstituteTests()

    nSubsMock = Substitute.For<IStringUtility>();
    sut = new StringsWorker(nSubsMock);

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

Set a method result for a specific input value: The Return () method

Suppose we want to customize our dependency so that each time we pass “ciao” as a parameter to Transform The method, it returns “peace”.

With Moq We use a combination of Setup and Returns.

moqMock.Setup(_ => _.Transform("ciao")).Returns("hello");

With NS replacement We do not use settings, but we communicate directly Returns.

nSubsMock.Transform("ciao").Returns("hello");

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

Now we do not care about the actual value transferred to Transform Method: We want that regardless of the kit, the method will always return “hello”.

With Moq, we are using It.IsAny<T>() And specify the type T:

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

With NS replacement, we are using Arg.Any<T>():

nSubsMock.Transform(Arg.Any<string>()).Returns("hello");

Set method result based on input filter: It.Is () vs. Arg.Is ()

Suppose we want to return a specific result only when a condition is met in the input parameter.

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

With Moq, we are using It.Is<T>(func) And we transmit expression as input.

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

in a similar way, With NS replacement, we are using Arg.Is<T>(func).

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

Small Trivia: For Nsubstitute, the filter is type Expression<Predicate<T>>, While for Moq it’s type Expression<Func<TValue, bool>>: Do not worry, you can write them the same way!

Exceptional throws

Because you need to check not only happy paths, but even those where an error occurs, you should write tests where the injected service throws an exception, and make sure that this exception is handled correctly.

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


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


nSubsMock.TransformAll(null).Throws<ArgumentException>();

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

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


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


nSubsMock.TransformAll(null).Throws(myException);

If you do not want to address this exception, but you want to distribute it, you can verify it this way:

Assert.Throws<ArgumentException>(() => sut.TransformArray(null));

Authentication of received calls: Verify () vs. Received ()

Sometimes, to figure out if the code is following the execution paths as expected, you may want to make sure that it is called a method with some parameters.

To verify this, you can use Verify method On Moq.

moqMock.Verify(_ => _.Transform("hello"));

Or, if you use N replaces, You can use Received method.

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

Similar to what we have seen before, you can use It.IsAny, It.Is, Arg.Any and Arg.Is To validate some properties of the parameters passed as input.

Verify the exact count of calls received

Other times, you may want to make sure it is called a method Exactly N times.

With Moq, You can add a parameter to Verify method:

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

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

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

With N replaces, On the contrary, you can specify only a defined value, which is added as a parameter to Received method.

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

nSubsMock.Received(3).Transform(Arg.Any<string>());

Zero calls received

As you may recall, the ridiculous dependence was made within the constructor, so each test method uses the same instance. This can cause some issues, especially when checking how many calls have received the dependency (because the number of calls received is cumulative for each previously tested test method). Therefore, we need to reset the received calls.

In NUnit, you can set a method that works before Any test method – but only if decorated with SetUp attribute:

[SetUp]
public void Setup()

  

Here we can reset the number of method references recorded on the dependency and make sure that our test methods always use Clear Cases.

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

[SetUp]
public void Setup()

    moqMock.Invocations.Clear();

While, With NS replacement, You can use ClearReceivedCalls():

[SetUp]
public void Setup()

    nSubsMock.ClearReceivedCalls();

for further reading

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

πŸ”— Documentation Moq | GitHub

πŸ”— Substitute documentation N replaces

If you already use Moq but have difficulty testing and setting up IHttpClientFactory Cases, I reviewed you:

How to Test HttpClientFactory with Moq | Code4IT

Finally, if you want to see the full code of this article, you can find it on GitHub; I wrote the exact same tests with the two libraries so you can compare them more easily.

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

Summary

In this article, we have seen how Moq and NSubstitute allow us to perform some basic operations when writing unit tests with C #. They are similar, but each has a specific set of functionality that is missing in the second directory – or, at least, I do not know if they exist in both.

Which directory do you use, Moq or Nsubstitute? Or maybe, another one?

Happy coding! 🐧

.

Source

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Popular Articles