DEV Community

loading...
Cover image for Moq vs NSubstitute - Who is the winner?
Cloud(x);

Moq vs NSubstitute - Who is the winner?

andreslozadamosto profile image Andres Lozada Mosto ・Updated on ・4 min read

In this article will compare two of most important mocking libraries for .Net (.Net Core and .Net Framework) NSubstitute and Moq.

What will we compare?

  • Simplicity
  • Readability
  • Behaviours

The fight begins πŸ’ͺ

Mock creation

Moq

var mock = new Mock<IRepository>();
Enter fullscreen mode Exit fullscreen mode

NSubstitute

var mock = Substitute.For<IRepository>();
Enter fullscreen mode Exit fullscreen mode

Moq uses a more representative notation. Anyone, just reading that line can know that we are creating a mock object.

Winner: Moq

Mocking properties

Moq

// Simple properties
mock.Setup(foo => foo.Users).Returns(userList);

// Hierarchy
mockUser.Setup(foo => foo.Address.Street).Returns(street);
Enter fullscreen mode Exit fullscreen mode

NSubstitute

// Simple properties
mock.Users.Returns(userList);

// Hierarchy
mockUser.Address.Street.Returns(street);
Enter fullscreen mode Exit fullscreen mode

NSubstitue has a simpler interface to set up the returns.

Winner: NSubstitue

Mocking methods

Moq

// Without parameters
mock.Setup(x => x.ActiveUsers()).Returns(userList);

// Matching by value
mock.Setup(x => x.SearchById(1)).Returns(user);

// Matching by any value of the parameter type
mock.Setup(x => x.SearchById(It.IsAny<int>())).Returns(user);

// Matching by custom logic
mock.Setup(x => x.SearchById(It.Is<int>(i => i < 10))).Returns(user);
Enter fullscreen mode Exit fullscreen mode

NSubstitute

// Without parameters
mock.ActiveUsers().Returns(userList);

// Matching by value
mock.SearchById(1).Returns(user);

// Matching by any value of the parameter type
mock.SearchById(Arg.Any<int>()).Returns(user);

// Matching by custom logic
mock.SearchById(Arg.Is<int>(i => i < 10)).Returns(user);
Enter fullscreen mode Exit fullscreen mode

Same here, NSubstitute has a simpler interface to set up the returns of the methods mocked.

Winner: NSubstitue

Matching arguments

Moq

// - It.IsAny<int>())
// - It.IsInRange(0, 10, Range.Inclusive) 
// - It.IsIn(Enumerable.Range(1, 5))
// - It.IsNotIn(Enumerable.Range(1, 5))
// - It.IsNotNull<string>())
// - It.IsRegex("abc"))
// - It.Is<int>(i => i < 10))
// - mock.Setup(x => x.Search(IsLarge())) //< custom
Enter fullscreen mode Exit fullscreen mode

NSubstitute

// - Arg.Any<int>())
// - Arg.Is<int>(i => i < 10))
Enter fullscreen mode Exit fullscreen mode

Moq provide us a lot more built-in options for matching arguments

Winner: Moq

Capturing parameter

Moq

mock.Setup(x => x.Add(It.IsAny<IUserModel>())).Returns((IUserModel user) => user.Username == "Andres");
Enter fullscreen mode Exit fullscreen mode

NSubstitute

mock.Add(Arg.Any<IUserModel>()).Returns(x => { return ((IUserModel)x[0]).Username == "Andres"; });
Enter fullscreen mode Exit fullscreen mode

With Moq, it is easier to get the arguments values before returning the mocked value and process them as needed.

Winner: Moq

Multiple matching

Moq

mock.Setup(x => x.SearchById(It.IsAny<int>())).Returns((int i) => userList.Skip(1).Take(1).First());
mock.Setup(x => x.SearchById(2)).Returns((int i) => userList.First());
Enter fullscreen mode Exit fullscreen mode

NSubstitute

mock.SearchById(Arg.Any<int>()).Returns(userList.Skip(1).Take(1).First());
mock.SearchById(2).Returns(userList.First());
Enter fullscreen mode Exit fullscreen mode

Both of them allow us to add as many match expressions that we need. If there is a conflict they will take the last expression that matches.

Winner: Tie

Callabacks

Moq

mock.Setup(x => x.SearchById(1))
                .Callback((int x) => parameterValue = x)
                .Returns(userList.First());

// Methods without return
mock.Setup(x => x.Save()).Callback(() => name = "aa");

// before and after
mock.Setup(x => x.SearchById(2))
                .Callback<int>(x => parameterValue = x)
                .Returns(userList.First())
                .Callback<int>(x => name = "andres");
Enter fullscreen mode Exit fullscreen mode

NSubstitute

mock.SearchById(1)
                .ReturnsForAnyArgs(x =>
                {
                    parameterValue = (int)x[0];
                    return userList.First();
                });

// Methods without return
mock.When(x => x.Save())
                .Do(x => name = "aa");


// before and after
mock.SearchById(2)
               .ReturnsForAnyArgs(x =>
               {
                   parameterValue = (int)x[0];
                   return userList.First();
               })
               .AndDoes(x => name = "andres");
Enter fullscreen mode Exit fullscreen mode

In this case Moq* provides a more readable experience adding a function called β€œCallback” on the chain call.

Winner: Moq

Multi-returns

Moq

mock.SetupSequence(x => x.Users)
                .Returns(users1)
                .Returns(users2)
                .Returns(users3);
Enter fullscreen mode Exit fullscreen mode

NSubstitute

mock.Search(Arg.Any<string>()).Returns(users1, users2, users3);
Enter fullscreen mode Exit fullscreen mode

Here both libraries are very similar right?.

Winner: Tie

Throwing Exceptions

Moq

mock.Setup(x => x.Save()).Throws<Exception>();
mock.Setup(x => x.Save()).Throws(new Exception("msj"));
Enter fullscreen mode Exit fullscreen mode

NSubstitute

mock.ActiveUsers().Returns(x => { throw new Exception(); });
mock.When(x => x.Save())
                .Do(x => { throw new Exception("msj"); });
Enter fullscreen mode Exit fullscreen mode

Moq is easier to recognize that the function will throw an exception.

Winner: Moq

Verify

Moq

// Setter
mock.VerifySet(x => x.Users = users);

// Getter
mock.VerifyGet(x => x.Users);

// Methods with matchting
mock.Verify(x => x.Search(It.IsAny<string>()));
mock.Verify(x => x.Search("aaa"), Times.Never());

// Occurrences
// - Times.Never
// - Times.Once
// - Times.AtLeastOnce
// - Times.AtMost(2)
// - Times.Exactly(2)
Enter fullscreen mode Exit fullscreen mode

NSubstitute

// Setter
mock.Received().Users;

// Getter
mock.Received().Users = users;

// Methods with matchting
mock.Received().Search("aa");
mock.DidNotReceive().Search("aaa");
mock.Received(2).Search("bb");

// Occurrences
// Nop

Enter fullscreen mode Exit fullscreen mode

NSubsitute has a simple way to verify that a method was called but Moq has more options to test how many times the method was executed.

Winner: Moq

Matching Generic Type Arguments

Moq

mock.Setup(m => m.AddUser(It.IsAny<It.IsSubtype<IUserModel>>())).Returns(true);
mock.Setup(m => m.AddUser(It.IsAny<UserModel2>())).Returns(false);
Enter fullscreen mode Exit fullscreen mode

NSubstitute

mock.AddUser<IUserModel>(Arg.Any<IUserModel>()).Returns(true);
mock.AddUser<IUserModel>(Arg.Any<UserModel2>()).Returns(false);
Enter fullscreen mode Exit fullscreen mode

Again, both provide an easy way to mock Generic Methods

Winner: tie


Well, how is it going? Who is winning?
Let’s see the current score

Syntax Moq NSubstitute
Mock creation βœ…
Mocking properties βœ…
Mocking methods βœ…
Matching arguments βœ…
Multiple matching tie tie
Callabacks βœ…
Multi-returns tie tie
Throwing Exceptions βœ…
Verify βœ…
Matching Generic Type Arguments tie tie

Moq is the winner!! πŸ˜€ πŸŽ‰

I really prefer Moq and I try to use it always but both are excellent options to use. Us, as developers, we should be able to work with both.

You can download the examples from my Github
https://github.com/andreslozadamosto/net-thoughts/tree/master/libraries/testing/MoqVsNSubstitute/MockingLibrariesExamples


Are you with me?
Do you prefer NSubstitue?
I forget to compare any behaviour?

Share your comments πŸ€™πŸ‘‡

Discussion (0)

pic
Editor guide