Sparky's Tool Tips: Moq.AutoMock
Brian Schroer
Posted on July 26, 2021
Probably the most important thing that makes .NET classes unit-testable is dependency injection (injecting interfaces, not implementations), usually via constructor injection.
Mocking libraries make it easier to generate "mock" interface implementations, and to verify that the interfaces were used as expected. Moq is the most popular .NET mocking library.
If you're using Moq, you may be interested in my SparkyTestHelpers.Moq and SparkyTestHelpers.MoqFluent NuGet packages. They provide an alternative to "It.IsAny" and "It.Is" syntax that I think is easier to write and read, and fluent assertions for verifications.
....lost of interfaces
The Moq.AutoMock NuGet package provides an "auto-mocker" container for Moq.
AutoMocker.CreateInstance<T> creates a new instance of the specified type, automatically generating Mocks for all of its constructor interface parameters. (The class must have a constructor where all of the parameters are interfaces):
Without AutoMocker:
var mockReader = new Mock<IReader>();
var mockFormatter = new Mock<IFormatter>();
var mockLogger = new Mock<ILogger>();
var foo = new Foo(
mockReader.Object, mockFormatter.Object, mockLogger.Object);
With AutoMocker:
var autoMocker = new AutoMocker();
var foo = autoMocker.CreateInstance<Foo>();
To .Setup or .Verify mock behavior, you can get the auto-generated mock via AutoMocker's "GetMock<TMock>" method:
autoMocker.GetMock<IFormatter>.Setup(x =>
x.Format(It.IsAny<decimal>()).Returns(x => x.ToString("###.00"));
You may find it advantageous to create a custom AutoMocker subclass for your project that sets up "happy path" behavior for some of your commonly used interfaces:
public class CustomAutoMocker : AutoMocker
{
// constructor
public CustomAutoMocker()
{
// Set up commonly used interfaces
Mock<IFormatter> mockFormatter = GetMock<IFormatter>();
//mockFormatter.Setup(x => ...
}
}
var autoMocker = new CustomAutoMocker();
var foo autoMocker.CreateInstance<Foo>();
// following tests will use Setups defined in the CustomAutoMocker
A custom AutoMocker subclass can also override the CreateInstance<T> method to perform additional logic when an instance of a specific type is created. For example, in a project using ApiControllers that I work on (which was not originally written with unit testing in mind), I detect construction of ApiController instances and automatically set up their .Request and .User properties:
public class CustomAutoMocker : AutoMocker
...
public new T CreateInstance<T>() where T : class
{
T instance = base.CreateInstance<T>();
var apiController = instance as ApiController;
if (apiController != null)
{
// Set up ApiController's Request and User
apiController.Request = new HttpRequestMessage();
apiController.Request.SetConfiguration(new HttpConfiguration());
apiController.User = BuildClaimsPrincipal();
}
return instance;
}
private ClaimsPrincipal BuildClaimsPrincipal()
{
// (code to build ClaimsPrincipal and
// assign it to Thread.CurrentPrincipal)
}
Mock.AutoMock and a custom AutoMocker subclass have greatly reduced the amount of repetitive and tedious mock setup code I need to write in my unit tests.
If you're using Moq, I highly recommend it.
Posted on July 26, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.