Что такое модульное тестирование (unit testing)?

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

Ответ

Модульное тестирование — это уровень тестирования ПО, при котором проверяется корректность работы отдельных, изолированных частей приложения (юнитов). Обычно юнитом считается один метод или функция, реже — небольшой класс. Цель — убедиться, что каждая часть кода работает правильно сама по себе.

Ключевые принципы (FIRST):

  • Fast (Быстрые): Тесты должны выполняться за доли секунды.
  • Isolated (Изолированные): Тест не должен зависеть от других тестов, внешних сервисов (БД, API) или состояния системы. Зависимости заменяются заглушками (mocks/stubs).
  • Repeatable (Повторяемые): Результат теста должен быть одинаковым при каждом запуске.
  • Self-validating (Самопроверяемые): Тест должен однозначно определять, пройден он или нет (Pass/Fail).
  • Timely (Своевременные): Пишутся до или параллельно с кодом (TDD).

Пример теста с использованием xUnit и Moq: Допустим, у нас есть сервис, который зависит от репозитория.

// Производственный код
public class OrderService
{
    private readonly IOrderRepository _repository;
    public OrderService(IOrderRepository repository) => _repository = repository;

    public Order GetOrder(int id) => _repository.GetById(id);
}

// Тест
public class OrderServiceTests
{
    [Fact]
    public void GetOrder_ValidId_ReturnsOrder()
    {
        // 1. ARRANGE (Подготовка)
        var expectedOrder = new Order { Id = 1, Total = 100 };
        var mockRepo = new Mock<IOrderRepository>(); // Создаём mock-объект
        mockRepo.Setup(repo => repo.GetById(1)).Returns(expectedOrder); // Настраиваем поведение

        var service = new OrderService(mockRepo.Object); // Внедряем зависимость

        // 2. ACT (Действие)
        var result = service.GetOrder(1);

        // 3. ASSERT (Проверка)
        Assert.NotNull(result);
        Assert.Equal(expectedOrder.Id, result.Id);
        Assert.Equal(expectedOrder.Total, result.Total);
        // Проверяем, что метод репозитория был вызван ровно один раз с правильным аргументом
        mockRepo.Verify(repo => repo.GetById(1), Times.Once);
    }
}

Популярные фреймворки для .NET: xUnit, NUnit, MSTest. Для создания заглушек — Moq, NSubstitute.