Средний ~25 мин чтения

Unit-тесты: изоляция и хорошие практики

Урок 2 из 5 в курсе Тестирование backend-приложений

Unit-тесты: изоляция и хорошие практики

unit-тест проверяет одну единицу логики изолированно; хороший unit-тест быстр, детерминирован и диагностирует конкретную проблему

Почему это важно: плохо написанные unit-тесты ломаются при безопасном рефакторинге, дают ложные сигналы и отбивают желание писать тесты

Главная идея

AAA-паттерн (Arrange-Act-Assert) структурирует тест; тест должен проверять одно поведение; название — документация

Как это выглядит на практике

  1. Arrange: создаём объект User с role: :admin.
  2. Act: вызываем user.can?(:delete_posts).
  3. Assert: ожидаем true.
  4. Тест называется: 'admin can delete any post'.
  5. Тест падает с понятным сообщением: expected true, got false.

Что происходит под капотом

  • Test double: заменитель зависимости в тестах. Виды: stub (возвращает значение), mock (проверяет вызовы), spy (записывает вызовы), fake (упрощённая реализация).
  • Dependency injection: зависимости передаются извне, что позволяет заменять их в тестах.
  • Parametrized tests: один тест с разными входными данными. Избегает дублирование.
  • describe/context/it — структура для группировки тестов по поведению.

Типичные ошибки и заблуждения

  • Ошибка: один тест на один метод. Один тест на одно ожидаемое поведение. Метод может иметь несколько тестов.
  • Ошибка: чем больше assertions в тесте, тем лучше. Одна assertion на тест; при падении сразу ясна причина.
  • Ошибка: тест, проверяющий реализацию, лучше документирует. Тестируй публичный интерфейс; рефакторинг внутренностей не должен ломать тесты.
  • Ошибка: shared state между тестами ускоряет setup. Shared state — источник flaky тестов и скрытых зависимостей между тестами.

Ключевые выводы

  • AAA: Arrange → Act → Assert. Каждый раздел явно разделён.
  • Одна assertion на тест: при падении сразу ясна причина.
  • Название теста — документация: 'should return 403 when user is not owner'.
  • Изоляция: тест не зависит от других тестов, БД, времени, сети.

Термины урока

AAA (Arrange-Act-Assert): паттерн структуры unit-теста.
Stub: тестовый двойник, возвращающий заданное значение.
Mock: тестовый двойник, проверяющий что метод был вызван с определёнными аргументами.
Dependency Injection: передача зависимостей извне, а не создание внутри.
Flaky test: тест, падающий не стабильно; часто из-за shared state или внешних зависимостей.

Связь с работой backend-разработчика

Правило хорошего теста: FIRST — Fast, Isolated, Repeatable, Self-validating, Timely. Если тест нарушает любой из этих принципов — это сигнал к рефакторингу.

Мини-разбор реальной ситуации

Разработчик пишет тест, который создаёт пользователя в реальной БД, вызывает сервис и проверяет результат. Тест: медленный (100ms), непредсказуемый (зависит от состояния БД), ломается при очистке. После инъекции мок-репозитория: тест 2ms, всегда зелёный, тестирует только бизнес-логику.

Что запомнить

  • AAA структура делает тест читаемым.
  • Тест = документация: назовите тест как бизнес-требование.
  • Изоляция: каждый тест независим от других.

Итог

Хорошие unit-тесты — это не бюрократия, а дизайн-инструмент. Они заставляют думать о зависимостях и интерфейсах до написания кода.