Our Experience With the Migration From Moq to NSubstitute

Since I wrote about how to migrate from Moq to NSubstitute, we decided to migrate our work projects as well. The migration was much simpler than anticipated and we got some nice benefits along the way.

 

Search and replace

We did the largest part of the migration with search & replace in Visual Studio. These substitutions got us nearly 95% of the way:

Search for Replace with
using Moq; using NSubstitute;
new Mock< Substitute.For<
Mock< [empty]
.Setup(x => x [empty]
)).Returns( ).Returns(
It.IsAny Arg.Any
.Object [empty]
.Verify(x => x. .Received(1).
, Times.Once) [empty]

With the exception of .Object you can run all the search and replace commands for the whole solution. The .Object part is widely used with *.resx files and will break the compiler if that token is missing.

After this first round, we had to do these changes by hand:

  1. Remove the leftover > (from Mock<)
  2. When the verify() method of Moq checked for a method to never be called, we had to manually delete Times.Never and switch from .Received(1) to .DidNotReceive().
  3. For other values than Times.Once() and Times.Never, we had to set the parameter for .Received() accordingly.

 

Careful with matchers

For the substitution in Moq and in NSubstitute the last matching configuration wins. Therefore, first specify the generic matchers with Arg.IsAny<T>, followed by the specific values you want to match.

We got some strange behaviour in NSubstitute when the specific values were instance variables. In that case the substitution worked, but the verification afterwards could not find a match. Should you run into this problem, use the generic approach with Arg.IsAny<T> instead of the instance variable if that works for your test case.

 

Throwing exceptions for void methods

While Moq did not differentiate between methods who return a value or void when it comes to throwing exceptions, NSubstitute does. You can use this syntax for void and non-void methods in NSubstitute:

 

Better tests due to less flexibility

There were about 5 tests that we could not migrate directly, because NSubstitute did not offer as much flexibility as Moq did. After a thorough review of the tests, we found a better and more robust way to test the same behaviour. The new tests communicate the reason of their existence much better and are a lot simpler to understand.

Should the migration of your tests not work with the direct search and replace approach, take a few minutes to improve the test. NSubstitute is powerful enough to test your application, but it may not offer all the unusual ways you could use in Moq.

 

Parting thoughts

We had to spend a few days to migrate our 500+ test fixtures to NSubstitute. This was work we had not planned for, but thanks to the comparable syntax, the effort was manageable.

Some of our test projects now run faster, while most of them have similar performance metrics. Nevertheless, we like the simplicity of NSubstitute and the clearer syntax.

Time will tell if this decision was right. Until then we are happy that we can focus on writing software and can stay far away of the SponsorLink drama.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.