NSubstitute vs Moq

NSubstitute vs Moq

posted in dotnet on

Comparing NSubstitute syntax with Moq, probably the most used mocking framework out there at the moment.

moq/moq4 :

nsubstitute/nsubstitute :

// 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.


Stuff that came into being during the making of this post
Tags: tutorial testing