A cheat sheet to migrate from Moq to NSubstitute
A quick reference to help the migration from Moq to NSubstitute.
Initialization: new Mock<T>() => Substitute.For<T>()
Moq.csvarmock=newMock<IService>();// or, if you don't need to customize and verify the mockvarmock=.Of<IService>();// when using the above, you can still get the mock instance using Mock.GetvarmockInstance=.Get();
NSubstitute.csvarmock=.For<IService>();
Argument matchers
Matches any value: It.IsAny<T>() => Arg.Any<T>()
Moq.cs.IsAny<string>()
NSubstitute.cs.Any<string>()// shorthand: use `default` im combination with `WithAnyArgs` methods// instead of the `Arg` syntax in (examples follow later)
Matches a specific value: It.Is<T>() => Arg.Is<T>()
Moq.cs.Is<string>(matcher=>==).Is<int>(matcher=>>=10&&<=20)
NSubstitute.cs.Is<string>(matcher=>==).Is<string>().Is<int>(matcher=>>=10&&<=20)// shorthand: use `value` directly instead of the `Arg` syntax (examples follow later)
Matches a generic type: It.IsAnyType() => TBD
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()
Method without arguments
Moq.csvarmock=newMock<IMyDependency>();..Method();.Verify(x=>.Method());
NSubstitute.csvarmock=.For<IMyDependency>();.Method();.Received().Method();
Method invoked with any arguments
Moq.csvarmock=newMock<IMyDependency>();..MethodWithArgument();.Verify(x=>.MethodWithArgument(.IsAny<string>()));
NSubstitute.csvarmock=.For<IMyDependency>();.MethodWithArgument();.Received().MethodWithArgument(.Any<string>());// or use `ReceivedWithAnyArgs` in combination with `default` instead of the `Arg` syntax.ReceivedWithAnyArgs().MethodWithArgument(default);
Method invoked with specific arguments
Moq.csvarmock=newMock<IMyDependency>();..MethodWithArgument();.Verify(x=>.MethodWithArgument(.Is<string>(match=>==)));
NSubstitute.csvarmock=.For<IMyDependency>();.MethodWithArgument();.Received().MethodWithArgument(.Is<string>(match=>==));// shorthand for the `Arg` syntax.Received().MethodWithArgument(.Is());// or directly use the value instead of the `Arg` syntax.Received().MethodWithArgument();
Number of invocations: Times.Exactly(N) => Received(N)
Moq.csvarmock=newMock<IMyDependency>();.MethodWithArgument();.MethodWithArgument();.MethodWithArgument();// is invoked.Verify(x=>.MethodWithArgument(.IsAny<string>()));// is invoked exactly once.Verify(x=>.MethodWithArgument(.Is<string>(match=>==)),.Once());// is invoked exactly x times.Verify(x=>.MethodWithArgument(.Is<string>(match=>==)),.Exactly(2));// there are also other options like `Times.Between(N, N)`, `Times.AtMost(N)`, `Times.AtLeast(N)`// these do not have a direct equivalent in NSubstitute
NSubstitute.csvarmock=.For<IMyDependency>();.MethodWithArgument();.MethodWithArgument();.MethodWithArgument();// is called.ReceivedWithAnyArgs().MethodWithArgument(default);// is called exactly once.Received(1).MethodWithArgument(.Is<string>(match=>==));// is called x times.Received(2).MethodWithArgument(.Is<string>(match=>==));
Is not invoked: Times.Never() => DidNotReceive()
Moq.csvarmock=newMock<IMyDependency>();..MethodWithArgument();.Verify(x=>.Method(),.Never());.Verify(x=>.MethodWithArgument(.Is<string>(match=>==)),.Never());
NSubstitute.csvarmock=.For<IMyDependency>();.MethodWithArgument();.DidNotReceiveWithAnyArgs().Method();// with argument check.DidNotReceive().MethodWithArgument(.Is<string>(match=>==));.DidNotReceive().MethodWithArgument(.Is<string>());// shorthand for the `Arg` syntax.DidNotReceive().MethodWithArgument();
Reset invocations: Reset() => ClearReceivedCalls()
Moq.csvarmock=newMock<IMyDependency>();..Method();.Verify(x=>.Method());.Reset();.Verify(x=>.Method(),.Never());
NSubstitute.csvarmock=.For<IMyDependency>();.Method();.Received().Method();.ClearReceivedCalls();.DidNotReceive().Method();
Task invocation
Moq.csvarmock=newMock<IMyDependency>();await..MethodAsync();.Verify(x=>.MethodAsync());
NSubstitute.csvarmock=.For<IMyDependency>();await.MethodAsync();// also works without `await` but results in a warningawait.Received().MethodAsync();
Setting the return value
Static return value: Setup().Returns() => Returns()
Moq.csvarmock=newMock<IMyDependency>();.Setup(m=>.MethodWithReturnValue()).Returns();varresult=..MethodWithReturnValue();.That(,.EqualTo());
NSubstitute.csvarmock=.For<IMyDependency>();.MethodWithReturnValue().Returns();varresult=.MethodWithReturnValue();.That(,.EqualTo());
Return value based on input: method arguments => callInfo
Moq.csvarmock=newMock<IMyDependency>();.Setup(m=>.MethodWithReturnValue(.IsAny<int>(),.IsAny<string>())).Returns((intinput,stringprefix)=>{}{});varresult=..MethodWithReturnValue(1,);.That(,.EqualTo());
NSubstitute.csvarmock=.For<IMyDependency>();// get the argument based on the type, and if needed include the index.MethodWithReturnValue(.Any<int>(),.Any<string>()).Returns(callInfo=>{.Arg<string>()}{.ArgAt<int>(0)});// using `ReturnsForAnyArgs` in combination with `default` instead of the `Arg` syntax.MethodWithReturnValue(default,default).ReturnsForAnyArgs(callInfo=>{.Arg<string>()}{.ArgAt<int>(0)});varresult=.MethodWithReturnValue(1,);.That(,.EqualTo());
Fine grained control over return value based on input
Moq.csvarmock=newMock<IMyDependency>();.Setup(m=>.MethodWithReturnValue(.IsAny<int>(),.IsAny<string>())).Returns((intinput,stringprefix)=>{}{});.Setup(m=>.MethodWithReturnValue(.Is<int>(i=>==1),.IsAny<string>())).Returns((intinput,stringprefix)=>{}{});varresult1=..MethodWithReturnValue(1,);// matches the second setup, its return value is used.That(,.EqualTo());varresult2=..MethodWithReturnValue(2,);// doesn't match the second setup so it uses the return value of the first setup.That(,.EqualTo());
NSubstitute.csvarmock=.For<IMyDependency>();.MethodWithReturnValue(.Any<int>(),).Returns(callInfo=>{.Arg<string>()}{.ArgAt<int>(0)});.MethodWithReturnValue(1,).Returns(callInfo=>{.Arg<string>()}{.ArgAt<int>(0)});// fallback: ReturnsForAll is used to set the return value for all calls// that don't have a specific setup (if the return type matches the generic).ReturnsForAll<string>();// fallback: using the callInfo to create the return value.ReturnsForAll<string>(callInfo=>{.Arg<string>()}{.Arg<int>()});// NOTE: the callbacks are invoked in the order they are defined// the last return value is used as the return value of the method// this can become problematic when using callbacks that have side effects (more on this later)// as a workaround, use `Configure` to ensure previous callbacks do not run// e.g. this is useful when previous callbacks throw exceptions.Configure().MethodWithReturnValue(10,).Returns();varresult1=.MethodWithReturnValue(1,);// matches the second setup, its return value is used.That(,.EqualTo());varresult2=.MethodWithReturnValue(2,);// doesn't match the second setup so it uses the return value of the first setup.That(,.EqualTo());varresult3=.MethodWithReturnValue(1,);// doesn't match any setup, thus the fallback is used.That(,.EqualTo());
Async (Task) return value: ReturnsAsync() => Returns()
Moq.csvarmock=newMock<IMyDependency>();.Setup(m=>.MethodWithReturnValueAsync(.IsAny<long>())).ReturnsAsync();varresult=await..MethodWithReturnValueAsync(1);.That(,.EqualTo());.Verify(x=>.MethodWithReturnValueAsync(.IsAny<long>()),.Once());
NSubstitute.csvarmock=.For<IMyDependency>();.MethodWithReturnValueAsync(default).ReturnsForAnyArgs();varresult=await.MethodWithReturnValueAsync(1);.That(,.EqualTo());await.ReceivedWithAnyArgs(1).MethodWithReturnValueAsync(default);
Multiple return values: SetupSequence().Returns() => Returns()
Moq.csvarmock=newMock<IMyDependency>();.SetupSequence(m=>.MethodWithReturnValue(.IsAny<int>())).Returns().Returns();varresult1=..MethodWithReturnValue(1);varresult2=..MethodWithReturnValue(2);varresult3=..MethodWithReturnValue(3);.That(,.EqualTo());.That(,.EqualTo());.That(,.);
NSubstitute.csvarmock=.For<IMyDependency>();.MethodWithReturnValue(default).ReturnsForAnyArgs(,);varresult1=.MethodWithReturnValue(1);varresult2=.MethodWithReturnValue(2);varresult3=.MethodWithReturnValue(3);.That(,.EqualTo());.That(,.EqualTo());// 👇 different from Moq, NSubstitute will return the last value for all subsequent calls.That(,.EqualTo());
NSubstitute.csvarmock=.For<IMyDependency>();// also supports multiple return values based on the input.MethodWithReturnValue(default).ReturnsForAnyArgs(callInfo=>.Arg<int>().ToString(),callInfo=>.Arg<int>().ToString());varresult1=.MethodWithReturnValue(1);varresult2=.MethodWithReturnValue(2);varresult3=.MethodWithReturnValue(3);.That(,.EqualTo());.That(,.EqualTo());.That(,.EqualTo());
Callbacks: Callback() => AndDoes()
Moq.csvarmock=newMock<IMyDependency>();varresult=;.Setup(m=>.MethodWithReturnValue(.IsAny<int>())).Returns().Callback((intx)=>{={};});..MethodWithReturnValue(1);.That(,.EqualTo());
NSubstitute.csvarmock=.For<IMyDependency>();varresult=;.MethodWithReturnValue(default).ReturnsForAnyArgs().AndDoes(callInfo=>{={.Arg<int>()};});.MethodWithReturnValue(1);.That(,.EqualTo());
Callback for void methods (or methods without a defined result): Callback() => When().Do()
Moq.csvarmock=newMock<IMyDependency>();varresult=;.Setup(m=>.MethodWithReturnValue(.IsAny<int>())).Callback((intx)=>{={};});..MethodWithReturnValue(1);.That(,.EqualTo());
NSubstitute.csvarmock=.For<IMyDependency>();varresult=;.WhenForAnyArgs(m=>.MethodWithReturnValue(default)).Do(callInfo=>{={.Arg<int>()};});.MethodWithReturnValue(1);.That(,.EqualTo());
Throwing Exceptions: Throws() => When().Do(() => throw)
Moq.csvarmock=newMock<IMyDependency>();.Setup(m=>.Method()).Throws(newInvalidOperationException());.Throws<InvalidOperationException>(()=>..Method());
NSubstitute.csvarmock=.For<IMyDependency>();.When(w=>.Method()).Do((callInfo)=>thrownewInvalidOperationException());.Throws<InvalidOperationException>(()=>.Method());
Automate Migration
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:
- https://github.com/AlbertoMonteiro/moq-to-nsubstitute
- https://github.com/moq/moq/issues/1374#issuecomment-1671241122
Conclusion
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!
Enjoying the blog?
Support my work
If you enjoyed this post and found it useful, consider supporting my work. It helps me keep creating and sharing content like this. Thank you!