Какую библиотеку для создания мок-объектов (Mocking) вы использовали в C#?

«Какую библиотеку для создания мок-объектов (Mocking) вы использовали в C#?» — вопрос из категории Тестирование, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Чаще всего использовал Moq — это де-факто стандарт в экосистеме .NET благодаря своей простоте и мощному API. Также знаком с NSubstitute.

Пример использования Moq для модульного теста:

Допустим, есть интерфейс репозитория и сервис, который от него зависит.

public interface IDataRepository
{
    int GetImportantValue();
}

public class MyService
{
    private readonly IDataRepository _repository;
    public MyService(IDataRepository repository) => _repository = repository;
    public int Calculate() => _repository.GetImportantValue() * 2;
}

Тест с Moq:

using Moq;
using Xunit;

public class MyServiceTests
{
    [Fact]
    public void Calculate_ReturnsDoubleOfRepositoryValue()
    {
        // 1. Arrange (Подготовка)
        var mockRepo = new Mock<IDataRepository>();
        // Настраиваем мок: при вызове GetImportantValue возвращает 10
        mockRepo.Setup(repo => repo.GetImportantValue()).Returns(10);

        var service = new MyService(mockRepo.Object);

        // 2. Act (Действие)
        var result = service.Calculate();

        // 3. Assert (Проверка)
        Assert.Equal(20, result); // Проверяем результат
        // Убеждаемся, что метод репозитория был вызван ровно один раз
        mockRepo.Verify(repo => repo.GetImportantValue(), Times.Once);
    }
}

Ключевые преимущества Moq:

  • Setup() — для определения поведения мока.
  • Verify() — для проверки взаимодействия (что метод был вызван с нужными параметрами).
  • Поддержка async методов, свойств, событий.

NSubstitute предлагает более лаконичный синтаксис (например, subRepo.GetValue().Returns(10)), что иногда предпочтительнее для читаемости.