How to Easily Create New Mock Instances in Unit Tests
Tags: csharp, testing, dotnet, tutorial
Published: 2023-09-27 12:00:00

We’re often told we should keep components light and focussed when building software. And with good reason too. Modules with a dedicated purpose are easier to work with; reuse; and test. However, one drawback is we need more of them to capture the same overall amount of logic.

Services can become more complex to instantiate when their dependency counts increase, as this means they’ll have more constructor parameters. This isn’t a problem when we use Inversion of Control frameworks and take advantage of Dependency Injection. However, we typically still need to provide the arguments explicitly – whether in the form of the real thing, a mock, or another type of substitute – in our tests.

In this article, we’ll look at how we can simplify the process of supplying these dependencies when writing tests.

## A Typical Approach to Writing Tests

Let’s assume we have a service called `MyService` and want to test it; to help us focus, we won’t include any methods, properties, or logic in our example. `MyService` has a constructor that takes two parameters: an `IDependency1` and an `IDependency2`.

``` csharp
public class MyService
{
    public MyService(
        IDependency1 dependency1,
        IDependency2 dependency2)
    {
    }
}
```

In tests we’ve written so far, we’ve instantiated the objects we want tested directly in the Arrange sections: they’d look similar in style to the following example:

``` csharp
[Test]
public void MyTest()
{
    // Arrange

    var service = new MyService(
        Mock.Of<IDependency1>(),
        Mock.Of<IDependency2>());

    // Act, Assert
}
```

This is a good approach when creating objects that have few (or no) dependencies. It strikes a good balance between the size of the test and keeping things simple: there isn’t too much code involved, and the lack of indirection means we can see all the logic without having to scroll or jump around on-screen while reading it.

In the previous example, we created and passed two default mocks as dependencies of `MyService`. But real-world systems are sometimes more complex than this, and it’s common for Arrange sections to require more code. This might be because:

* We need to set up various members (methods and properties) of the mocks before passing them in.

* We have more than two dependencies, especially if we break down systems while following the Single Responsibility Principle.

When repeated across many tests, we can easily end up with lots of duplicated code. To make things worse, we’ll have to make as many changes as there are copies if any of the dependencies change.

## Taking a Dry-er Approach

When setup code is identical, it’s tempting to follow the DRY principle (Don’t Repeat Yourself). One approach I’ve seen extracts the SUT (system under test) from the individual-test level and moves it to the test-fixture (i.e. class) level. As shown in the following example, this solves the problem of duplicating code while freeing up the Arrange sections of tests.

``` csharp
public class MyServiceTests
{
    private MyService _service = new MyService(
        Mock.Of<IDependency1>(),
        Mock.Of<IDependency2>());

    [Test]
    public void MyTest()
    {
        // Arrange

        // Act, Assert
    }
}
```

If any aspect of `MyService` or its dependencies are stateful, we can reset them in between tests using [setup methods](https://webdeveloperdiary.substack.com/p/3-nunit-attributes-you-shouldnt-forget-about); this is recommended when using NUnit, but may not be necessary with other testing frameworks.

While this approach works, I personally tend to not use it for two reasons:

* I try to avoid using state where possible.

* Customising an SUT’s dependencies for different tests is no longer an option.

The first point is a style preference: I find having variables as tightly scoped as possible helps when keeping track of things, but I know not everyone shares this view. The second however, is important regardless style: your SUT’s dependencies may need to be configured differently depending on what’s being tested.

## Making Things Tweakable

The following example shows how we can address both points by creating a factory method for our SUT. The method takes two parameters, one for each dependency. A dependency will be used if its corresponding argument isn’t `null` and will fall back to a value defined in the factory otherwise. In this example, this value is a default mock, but it’s possible to add setups if necessary. The parameters have default values of `null`, so in the simplest case we don’t need to provide any arguments. This helps to keep the test code to a minimum.

``` csharp
public class MyServiceTests
{
    private static MyService CreateMyService(
        IDependency1? dependency1 = null,
        IDependency2? dependency2 = null)
    {
        var service = new MyService(
            dependency1 ?? Mock.Of<IDependency1>(),
            dependency2 ?? Mock.Of<IDependency2>());

        return service;
    }

    [Test]
    public void MyTest()
    {
        // Arrange

        var service = CreateMyService();

        // Act, Assert
    }
}
```

If a test has requirements uncommon to others in the fixture, this gives us the flexibility to set up one (or more) of our SUT’s dependencies in a bespoke way and pass it in when calling the factory method. If we wanted `dependency2` in the preceding example to be a [strict](https://webdeveloperdiary.substack.com/p/use-strict-mocking-in-moq-to-auto-verify-setups) mock, we can see how to achieve this in the following code.

``` csharp
public class MyServiceTests
{
    private static MyService CreateMyService(
        IDependency1? dependency1 = null,
        IDependency2? dependency2 = null)
    {
        var service = new MyService(
            dependency1 ?? Mock.Of<IDependency1>(),
            dependency2 ?? Mock.Of<IDependency2>());

        return service;
    }

    [Test]
    public void MyTest()
    {
        // Arrange

        var service = CreateMyService(
            dependency2: new Mock<IDependency2>(
                MockBehavior.Strict).Object);

        // Act, Assert
    }
}
```

## Summary

While following the Single Responsibility Principle can have many benefits, it can lead to modules having more dependencies. This is usually most noticeable in tests where you typically call constructors explicitly while manually providing arguments.

One way to keep test code to a minimum is to extract the instantiation of SUTs to the fixture level. While this might make them less flexible for tests with different requirements, you can build on this approach. By using a factory to create testing subjects, you can balance tidiness with functionality, writing code for custom dependencies only in tests where they’re needed.

---

Thanks for reading!

This article is from my [newsletter](https://webdeveloperdiary.substack.com/?sd=pf). If you found it useful, please consider subscribing. You’ll get more articles like this delivered straight to your inbox (once per week), plus bonus developer tips too!