Reasons for changing Moq:
The author of Moq Library has recently decided to add SponsorLink to their project. This implies that in order to identify sponsors it extracts the email address configured in git without any formal consent. This approach might raise GDPR issues.
If the extracted email is linked to a sponsor, an information message is shown in the build result containing a thank you note. In the other case, a warning message asking for sponsorship is shown in the output. This can break the build if warnings are treated as errors. Another downside of having the latest version without paying a sponsorship might be delayed time in builds.
Unfortunately, with their recent actions, the author has lost the trust of developers worldwide and does not seem to want to reconsider their position. We cannot safely continue using newer versions of their library in this state, and the return of SponsorLink to Moq seems to be only a matter of time.
The replacement is necessary as Moq will get new versions that we will not be upgrading to. So, it will eventually become an outdated dependency that we have in our applications.
What to choose over Moq?
Some of the advantages of using a 3rd party for the job in this case are the clean fluent syntax their APIs provide and the ability to write fast, predictable, and repeatable tests with minimal configuration. When deciding between alternatives for Moq, we took into consideration the following factors.
The popularity of a framework is in general directly proportional to its stability and support. A higher usage is correlated with more coding examples, more resources and more fixed issues, as well as a larger community around it.
Following Moq, NSubstitute is at the moment the second most popular lightweight library for creating fake objects.
There seems to be no significant performance difference that would make one mocking library noticeably faster than the other. All of the popular ones are lightweight and efficient, all based on Dynamic Proxy Generation. This means that when faking an object, it generates a dynamic proxy class at runtime, which implements the interfaces that the real mocked object does, thus allowing method call interception and properties access.
Ease of use and syntax preference
Even though opinions can be subjective on this matter, this represented an important factor in the decision. The following table contains the code syntax changes that we compared given our most common usages.
In the case of our team, we reached a consensus on the NSubtitute syntax straight away. We preferred it even over the existent Moq syntax, and this represented the decisive factor ultimately.
What does it take to migrate the code syntax from Moq to NSubstitute?
To speed up the syntax substitution part of the migration process from Moq to NSubstitute, there are regex expressions that can help us find and replace most of the mock code in the unit tests. You can find a list of such here.
However, there are some limitations to this approach. First, the regex expressions did not work in some cases where our code was formatted differently.
Another implied change is encountered whether picking NSubstitute or FakeItEasy. Whenever passing a fake object in the constructor call of a class, “.Object” access must be removed. As with the alternative libraries, the code in this case is considered self-explanatory and doesn’t require to use “.Object” like in the case of Moq.
A third required manual change identified would be finding a way to substitute the call of the Moq Callback() method. Here’s an example of a callback setup substitution.
If an additional behaviour besides returning values needs to be set up, or in the case of mocking methods returning void, you can use “When” and “Do” methods call chain provided by NSubstitute. The parameters of a method can be accessed using the “CallInfo” object passed in the lambda function provided to the “Do” method.
How to get our tests all green again?
After syntax is completely substituted, do not expect all tests to be passing on the first run 😊 as there are some other implications. One of them is the need to use a different argument-matching approach for the cases where there are no implicit equality comparers (e.g. Lists or Expressions). In the case of lists passed as arguments, “SequenceEquals” and argument matching should be used instead, like in the following examples:
_fake.Method(Arg.Is<List<int>>(x => x.SequenceEqual(list))).Returns(true);
_fake.Method(Arg.Is<IEnumerable<int>>(x => x.SequenceEqual(list))).Returns(true);
_fake.Method(Arg.Is<ICollection<int>>(x => x.SequenceEqual(list))).Returns(true);
In the case of expression functions given as parameters, we decided to go with a generic argument-matching approach. Here’s an example:
_amsRepositoryFake.GetById(entityId, Arg.Any<Expression<Func<T, object>>>()).Returns(…);
Before this, when specifying the expression arguments for mocking repository “GetById” or “GetDbSet” methods, we were specifying the included properties for the query like “x => x.Prop1, x => x.Prop2, … “. That didn’t work anymore with NSubstitute.
Here’s the signature of the mocked method for a better understanding:
T GetById<T>(int entityId, params Expression<Func<T, object>> propertyToInclude) where T : class, IEntity;
As a last implied change, if you’re trying to fake the Entity Framework “DbSet”, don’t forget to include “IQueryable” as a substituted interface, like in the following example.
Having to replace Moq was not ideal. At first, it seemed to be a long-running task and not something comfortable to do on short notice. However, there are tools and resources that can make the migration easier. I hope this small guide can help with that and ensure a smooth transition for your projects.
Here’s the link with the regex expression’s if you were about to scroll back up for it.