Cleaner unit test mocking in C# with NSubstitute

Published on in C# and Elsewhere

The NSubstitute package simplifies how mock implementations are created and how mocks are used.

Table of contents

Moq

I have previously used Moq, "the most popular and friendly mocking library for .NET," to do mocking in unit tests.

Example from Nick Chapsas's video on the Moq package (_sut = system under test):

private readonly CustomerService _sut;
private readonly ICustomerRepository _customerRepositoryMock = new Mock<ICustomerRepository>();
private readonly ILoggingService _loggerMock = new Mock<ILoggingService>();

public CustomerServiceTests()
{
    _sut = new CustomerService(_customerRepositoryMock.Object, _loggerMock.Object);
}

[Fact]
public async Task GetByIdAsync_ShouldReturnCustomer_WhenCustomerExists()
{
    // ...

    // Mock implementation
    _customerRepositoryMock.Setup(x => x.GetByIdAsync(customerId))
        .ReturnsAsync(customerDto);

    // ...
}

NSubstitute

Nick Chapsas's video on the NSubstitute package convinced me that NSubstitute, "a friendly substitute for .NET mocking libraries," could be nicer.

Example from the video:

private readonly CustomerService _sut;
private readonly ICustomerRepository _customerRepository = Substitute.For<ICustomerRepository>();
private readonly ILoggingService _logger = Substitute.For<ILoggingService>();

public CustomerServiceTests()
{
    _sut = new CustomerService(_customerRepository, _logger);
}

[Fact]
public async Task GetByIdAsync_ShouldReturnCustomer_WhenCustomerExists()
{
    // ...

    // Mock implementation
    _customerRepository.GetByIdAsync(customerId).Returns(customerDto);

    // ...
}

Differences to Moq

  • No need to use .Object in various places.
  • Creating mock implementations is more straightforward.