A cheat sheet to migrate from Moq to NSubstitute

profile
Tim Deschryver
timdeschryver.dev

Initialization: new Mock<T>() => Substitute.For<T>() link

Argument matchers link

Matches any value: It.IsAny<T>() => Arg.Any<T>() link

Matches a specific value: It.Is<T>() => Arg.Is<T>() link

Matches a generic type: It.IsAnyType() => TBD link

Moq's helpers It.IsAnyType, It.IsValueType, and It.IsSubtype<T> are currently not supported by NSubstitute. Keep an eye on this issue #634 for updates.

Testing method invocations: Verify() => Received() link

Method without arguments link

Method invoked with any arguments link

Method invoked with specific arguments link

Number of invocations: Times.Exactly(N) => Received(N) link

Is not invoked: Times.Never() => DidNotReceive() link

Reset invocations: Reset() => ClearReceivedCalls() link

Task invocation link

Setting the return value link

Static return value: Setup().Returns() => Returns() link

Return value based on input: method arguments => callInfo link

Fine grained control over return value based on input link

Async (Task) return value: ReturnsAsync() => Returns() link

Multiple return values: SetupSequence().Returns() => Returns() link

Callbacks: Callback() => AndDoes() link

Callback for void methods (or methods without a defined result): Callback() => When().Do() link

Throwing Exceptions: Throws() => When().Do(() => throw) link

Automate Migration link

Because both syntaxes resemble each other, it is possible to use a couple of smart find and (RegExp) replace commands to help with the migration. These are not perfect, but they can be an enoourmous boost to get you started, and migrate 80% of your codebase in a matter of minutes.

Here are a few that I used. Before using them, make sure that you're working on a clean branch.

Find Replace
using Moq using NSubstitute
new Mock<(.*)>\(\) Substitute.For<$1>()
Mock<(.*?)> $1
\.Setup\([\w\s]*=>[\w\s]*(.*)\) $1
\.ReturnsAsync\( .Returns(
It\.IsAny Arg.Any
It\.Is Arg.Is
\.Object (be careful here as it may also replace other non-moq properties)
((\w+)|(\w+\s+))\.Verify\([\w\s]*=>[\w\s]*\.(.*)\)((.*?)), Times.Never\(\)\) await $1.DidNotReceive().$4)
\.Verify\([\w\s]*=>[\w\s]*\.(.*)\)((.*?)), .DidNotReceive().$1)
((\w+)|(\w+\s+))\.Verify\([\w\s]*=>[\w\s]*\.(.*)\)((.*?)), Times\.(Once(\(\))?|Exactly\((?<times>.*)\))\) await $1.Received(${times}).$4)
\.Verify\([\w\s]*=>[\w\s]*\.(.*)\)((.*?)), Times\.(Once(\(\))?|Exactly\((?<times>.*)\))\) Received(${times}).$1)
new AutoMoqCustomization new AutoNSubstituteCustomization
using AutoFixture\.AutoMoq using AutoFixture.AutoNSubstitute

I based mine implementation of these expression on the following resources:

Conclusion link

In this cheat sheet, we've seen the syntax differences between Moq and NSubstitute, more specifically how to convert Moq code to NSubstitute code. We've also touched on how to automate the migration of your codebase.

What I like about NSubstitute is that it's a lot more lightweight than Moq, and it doesn't require a lot of wrapping to mock interfaces. This makes the syntax more compact and easier to read.

For more information on NSubstitute, take a look at the NSubstitute documentation.

Feel free to update this blog post on GitHub, thanks in advance!

Join My Newsletter (WIP)

Join my weekly newsletter to receive my latest blog posts and bits, directly in your inbox.

Support me

I appreciate it if you would support me if have you enjoyed this post and found it useful, thank you in advance.

Buy Me a Coffee at ko-fi.com PayPal logo

Share this post