NSubstitute vs Moq
posted in dotnet on • by Wouter Van SchandevijlComparing NSubstitute syntax with Moq, probably the most used mocking framework out there at the moment.
moq/moq4 :
// All examples assume
public interface ICalculator
{
int Add(int a, int b);
int Divide(int n, int divisor, out float remainder);
string Mode { get; set; }
void SetMode(string mode);
}
// Moq
Mock<ICalculator> moq = new Mock<ICalculator>();
// NSubstitute
ICalculator nsub = Substitute.For<ICalculator>();
Basic example
Notice how NSubstitute dropped all the ceremony code required by Moq.
// Moq
var moq = new Mock<ICalculator>();
moq.Setup(calc => calc.Add(1, 2)).Returns(3);
Assert.AreEqual(3, moq.Object.Add(1, 2));
// NSubstitute
// Saves you a whopping 20 characters :)
var nsub = Substitute.For<ICalculator>();
nsub.Add(1, 2).Returns(3);
Assert.AreEqual(3, nsub.Add(1, 2));
Matching arguments
Moq
// It.
moq.Setup(calc => calc.Add(It.IsAny<int>(), It.Is<int>(b => b % 2 == 0))).Returns(3);
//Moq also has
//- It.IsRegex("", , RegexOptions.IgnoreCase)
//- It.IsInRange(0, 1, Range.Inclusive)
NSubstitute
// Arg.
nsub.Add(Arg.Any<int>(), Arg.Is<int>(b => b % 2 == 0)).Returns(3);
Verification
Moq
moq.Object.Add(1, 1);
moq.Object.Add(1, 1);
moq.Verify(calc => calc.Add(1, It.IsAny<int>()), Times.Exactly(2));
// Property
moq.VerifyGet(calc => calc.Mode, Times.Never);
NSubstitute
nsub.Add(1, 1);
nsub.Add(1, 1);
nsub.Received(2).Add(1, Arg.Any<int>());
// Property
var requiredAssignmentForCompiler = nsub.DidNotReceive().Mode;
Out and ref
ref
works in both frameworks exactly the same as out
.
Moq
float remainder = 0.4F;
moq.Setup(calc => calc.Divide(12, 5, out remainder)).Returns(2);
remainder = 0;
Assert.AreEqual(2, moq.Object.Divide(12, 5, out remainder));
Assert.AreEqual(0.4F, remainder);
NSubstitute
float remainder;
nsub.Divide(12, 5, out remainder).Returns(x => {
x[2] = 0.4F; // [2] = 3th parameter = remainder
return 2;
});
remainder = 0;
Assert.AreEqual(2, nsub.Divide(12, 5, out remainder));
Assert.AreEqual(0.4F, remainder);
Exceptions
Moq
moq.Setup(calc => calc.Add(1, 1)).Throws<InvalidOperationException>();
Assert.Throws<InvalidOperationException>(() => moq.Object.Add(1, 1));
moq.Setup(calc => calc.SetMode("HEX")).Throws(new ArgumentException());
Assert.Throws<ArgumentException>(() => moq.Object.SetMode("HEX"));
NSubstitute
using NSubstitute.ExceptionExtensions;
nsub.Add(1, 1).Throws(new InvalidOperationException());
Assert.Throws<InvalidOperationException>(() => nsub.Add(1, 1));
nsub.When(x => x.SetMode("HEX")).Throw<ArgumentException>();
Assert.Throws<ArgumentException>(() => nsub.SetMode("HEX"));
// The extension method syntax is much cleaner
// Without it, the setup becomes the following
nsub.Add(1, 1).Returns(x => { throw new InvalidOperationException(); });
nsub.When(x => x.SetMode("HEX")).Do(x => { throw new ArgumentException(); });
Summary
I find Moqs Func<T1, T2, ...>
overloads they have provided for .Return
very useful.
NSubstitute requires some more typing to achieve the same .Return
capabilities but
you do get to treat methods and properties alike compared to Moq who’s stuck with VerifyGet
.
Because of this NSubstitute got better discoverability inside an IDE while Moq
continues to struggle with a whole bunch of deprecated ways of doing things.
The drop of .Setup()
and .Object
for all cases is very win for NSubstitute.