Isolate your Components in Tests: How to Mock your Dependencies
Tags: csharp, dotnet, testing, tutorial
Published: 2023-06-07 14:09:00

We previously mentioned that unit tests act as basic checks for our app’s components. We also looked at how to write tests where we passed values into a calculation and compared the outputs with expected results. In these tests, we fed our sample inputs directly into a method that took a number, squared it, and then returned the result. No additional components were needed in the process.

However, things aren’t always that straightforward.

Sometimes, the logic in our services will rely on more than one component. In fact, it’s often a good idea to separate responsibilities when designing software modules. By keeping a module’s logic focussed to a specific area, it has a single identifiable purpose. This in turn means that we can reuse that module wherever it’s needed without having to bring in other features and capabilities that may not be immediately relevant. Furthermore, we can name the module more meaningfully, potentially making the codebase easier to understand.

In a unit test, we want to test a single component only – not a workflow. If the subject under test has dependencies, we deliberately want to exclude them from the test. That way, we’ll know exactly where to focus our debugging efforts if there’s ever a problem. One way to do this is Mocking.

## The Problem so Far
We started the series by wanting to be able to calculate the hypotenuse of a triangle. To do so, we would need to do three things:

1. Multiply a number by itself to find its square. We would do this for two numbers.

2. Calculate the sum of the two values obtained from step 1.

3. Find the square root of the result from step 2.

As part of completing step 1, we created a `MultiplicationService` that could square any given number. Focussing on step 2, let’s create a new `CalculationService` that:

* Accepts two separate numbers as input values.

* Squares them in the `MultiplicationService`.

* Adds the two results together.

The code for this might look like the following:

``` csharp
public class CalculationService
{
    private readonly IMultiplicationService _multiplicationService;

    public CalculationService(IMultiplicationService multiplicationService)
    {
        _multiplicationService = multiplicationService;
    }

    public int SumOfSquares(int a, int b)
    {
        int aSquared = _multiplicationService.Square(a);
        int bSquared = _multiplicationService.Square(b);
        return aSquared + bSquared;
    }
}
```

## Writing the Test
We can see that `SumOfSquares` makes use of `Square` from `MultiplicationService`. To ensure that we only test logic within the `SumOfSquares` method, we can use a library called Moq to mock out `MultiplicationService` in our C# unit tests. To do this we first create an interface for `MultiplicationService` that contains all of its public methods:

``` csharp
public interface IMultiplicationService
{
    int Square(int number);
}
```

Once `MultiplicationService` implements it, we can write our unit test. A first attempt might look like this:

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

    var multiplicationService = Mock.Of<IMultiplicationService>();
    var service = new CalculationService(multiplicationService);

    // Act

    var result = service.SumOfSquares(3, 4);

    // Assert

    Assert.That(result, Is.EqualTo(25));
}
```

However, we’ll see that the test fails if we run it:

```
Expected: 25
But was:  0
```

Why did this fail?

If we look at our test, we can see that we provided a mock of `IMultiplicationService`. However, we didn’t configure it to return any values. We can do this by modifying the declaration slightly:

``` csharp
var multiplicationService = Mock.Of<IMultiplicationService>(s =>
    s.Square(3) == 9 &&
    s.Square(4) == 16);
```

Here, we’re saying that:

* When we call `Square` with `3`, we want our mock to return a value `9`.

* When we call `Square` with `4`, we want `16` to be returned.

By doing this, we can be sure that the logic in `SumOfSquares` is correct, even if the implementation of `Square` changes such that its results become unreliable. After all, we’re currently writing a unit test: it should only test the logic of a single component, not the overall workflow. After the modification, our test would look like this:

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

    var multiplicationService = Mock.Of<IMultiplicationService>(s =>
        s.Square(3) == 9 &&
        s.Square(4) == 16);

    var service = new CalculationService(multiplicationService);

    // Act

    var result = service.SumOfSquares(3, 4);

    // Assert

    Assert.That(result, Is.EqualTo(25));
}
```

As shown in Image 1, we should see that our test now passes when we run it.


![The Visual Studio Test Explorer showing all tests passed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqre1h9y512k6kkazl75.png)
<figcaption>Image 1: The CalculationServiceCanCalculateSumOfSquares test has passed</figcaption>

## Summary
When writing unit tests, you want to test your components in isolation. With components that have dependencies, one way of limiting the scope of logic being tested is by mocking those dependencies. In C#, you can use Moq to do this. When creating a mock, it’s possible to specify its behaviours. In other words, you can configure it to return a specific value whenever it is given a certain input value.

By doing this, you can focus each test on a specific area of the code. With enough unit tests, you’ll be able to build up an overview of your app. And if something goes wrong, your hard work will pay off because your tests will give you a good idea of where the problem lies.

---

Thanks for reading!

This series aims to cover the basics of software testing, giving you more confidence in your code and how you work with it.

If you found this article useful, please consider signing up for my weekly [newsletter](https://webdeveloperdiary.substack.com/?sd=pf) for more articles like this delivered straight to your inbox (link goes to Substack).