Sparky's Tool Tips: Moq.AutoMock

sparky

Brian Schroer

Posted on July 26, 2021

Sparky's Tool Tips: Moq.AutoMock

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);
Enter fullscreen mode Exit fullscreen mode

With AutoMocker:

var autoMocker = new AutoMocker();
var foo = autoMocker.CreateInstance<Foo>();
Enter fullscreen mode Exit fullscreen mode

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"));
Enter fullscreen mode Exit fullscreen mode

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 => ...
    }
}
Enter fullscreen mode Exit fullscreen mode
    var autoMocker = new CustomAutoMocker();
    var foo autoMocker.CreateInstance<Foo>();
    // following tests will use Setups defined in the CustomAutoMocker
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
sparky
Brian Schroer

Posted on July 26, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related