How to Set Up Mocks in Unit Tests to Return Default Objects
Tags: csharp, testing, dotnet, tutorial
Published: 2023-08-16 13:08:00

If you’ve been following this series, you’ll have noticed that we use mocks often in our unit and integration tests. (If you’re a new reader, welcome – you’re invited to browse the [archive](https://webdeveloperdiary.substack.com/archive).) We set up the mocks in the Arrange sections of our tests to either return a value, or to perform some logic required for the test.

In some scenarios, all we need is for a mock to return a default object instance. Complex objects and services can have multiple dependencies, meaning we may need to set up this behaviour on many mocks. While it’s not difficult to do so, it increases the overall amount of test code.

This week, we’ll look at a way to keep setup code to a minimum in these situations.

## Setting the Scene

Let’s imagine we’re writing a service for an online shop. Its purpose is to generate reports for sales orders, and we have models to represent a customer; an order; and a report that combines parts of these two data.

``` csharp
public class Customer
{
    public int Id { get; set; }
    public string? Name { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public string[]? ProductsOrdered { get; set; }
}

public class OrderReport
{
    public string? CustomerName { get; set; }
    public string[]? ProductsOrdered { get; set; }
}
```

We also have three interfaces: one for a customer data repository, one for an orders repository, and one for a service containing references to the data repositories.

``` csharp
public interface ICustomerRepository
{
    Customer GetById(int id);
}

public interface IOrderRepository
{
    Order GetById(int id);
}

public interface IRepositories
{
    ICustomerRepository CustomerRepository { get; set; }
    IOrderRepository OrderRepository { get; set; }
}
```

Here’s the code for our reports service so far:

``` csharp
public class OrderReportsService
{
    private readonly IRepositories _repositories;

    public OrderReportsService(IRepositories repositories)
    {
        _repositories = repositories;
    }

    public OrderReport GetOrderReport(int orderId)
    {
        var order = _repositories.OrderRepository
            .GetById(orderId);

        var customer = _repositories.CustomerRepository
            .GetById(order.CustomerId);

        var report = new OrderReport
        {
            CustomerName = customer.Name,
            ProductsOrdered = order.ProductsOrdered
        };

        return report;
    }
}
```

## Writing a Test

We want a simple test to check that everything’s connected, and that we can get a (non-null) report by calling `GetOrderReport` on our service. We’ve created and set up three mocks. The two repository mocks simply return unmodified default objects for the return type; the `IRepositories` mock returns the mocked repositories.

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

    var customerRepository = Mock.Of<ICustomerRepository>(cr =>
        cr.GetById(It.IsAny<int>()) == new Customer());


    var orderRepository = Mock.Of<IOrderRepository>(or =>
        or.GetById(It.IsAny<int>()) == new Order());


    var repositories = Mock.Of<IRepositories>(r =>
        r.CustomerRepository == customerRepository &&
        r.OrderRepository == orderRepository);

    var reportsService = new OrderReportsService(repositories);

    // Act

    var report = reportsService.GetOrderReport(1);

    // Assert

    Assert.That(report, Is.Not.Null);
}
```

## Tidying Up

By default, mocks created in Moq return empty values (i.e. `null` for reference types, as is the case here). However, this behaviour changes when we set the `DefaultValue` property to `DefaultValue.Mock`. Mocks will instead return a mock of the requested type (if the type can be mocked). We can use this to tidy our test up a bit.

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

    var repositories = new Mock<IRepositories>
    {
        DefaultValue = DefaultValue.Mock
    };

    var reportsService = new OrderReportsService(
        repositories.Object);

    // Act

    var report = reportsService.GetOrderReport(1);

    // Assert

    Assert.That(report, Is.Not.Null);
}
```

## Summary

Mocking is common when writing unit and integration tests. By default, Moq returns empty values for properties and methods that haven’t been explicitly set up. If your tests involve configuring multiple mocks to return unmodified object instances, it might be worth considering setting the `DefaultValue` property on your mocks to `DefaultValue.Mock`; mocks will then return mocks of the requested types. Ultimately, you’ll have less code to write while still maintaining the same functionality.

---

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!