gitaspen docs

Тестирование

Что покрывать тестами, какими именно и где они лежат. Документ общий для фронта и бэка: слои разные, принцип один — тест проверяет наблюдаемое поведение через границу, а не внутреннее устройство.

6 минут

Что покрывать тестами, какими именно и где они лежат. Документ общий для фронта и бэка: слои разные, принцип один — тест проверяет наблюдаемое поведение через границу, а не внутреннее устройство.

Место в цепочке

Откуда пришлиЭтот документКуда ведёт
код разложен по слоям (BMFP / BMBP)что и как покрывать, где хранить тестысборка релиза, где прогон тестов — условие выпуска

Что этот документ оставляет следующему: набор проверок, который запускается одной командой и даёт однозначный ответ «можно выпускать». Тесты, которые надо запускать вручную и толковать глазами, эту роль не выполняют.


Что проверять на каждом слое

Границы слоёв задают, что считать поведением, а что — устройством.

Бэкенд:

СлойЧто проверяетсяЧто подменяется
core (логика, сценарии)правила предметной области: расчёты, переходы состояний, отказыхранилище и внешние клиенты
apiконтракт: коды ответов, форма конверта, проверка входных данных, правасценарии слоя core
infrastructureзапросы к хранилищу и разбор ответов внешних системсама внешняя система
сквознойпуть запроса целиком на поднятых зависимостяхничего

Фронт:

СлойЧто проверяетсяЧто подменяется
domain (состояния, сервисы)расчёты, правила формы, последовательность вызововклиенты infrastructure
infrastructure/clientsразбор конверта, проверка ответа схемой, обработка ошибкисеть
boundaryчто видит и делает пользователь: отображение, ввод, реакция на ошибкусервисы domain

Логика проверяется там, где она живёт. Если правило можно проверить только через интерфейс, оно оказалось не в том слое.


Виды тестов и их доля

ВидЧто даётЧего стоит
на слой (изолированные)быстрый и точный ответ, где сломалосьне ловит ошибки на стыках
на связку (несколько слоёв, настоящее хранилище)ловит стыки: схема, запросы, транзакциимедленнее, нужна среда
сквознойподтверждает, что путь работает целикомсамый медленный и хрупкий

Основной объём — изолированные и на связку. Сквозных немного: они покрывают главные сценарии (вход, ключевая операция, оплата), а не каждую ветку.

Соотношение выводится из цели: набор должен отрабатывать достаточно быстро, чтобы его запускали перед каждым изменением. Набор, который идёт полчаса, перестают запускать.


Правила

Тест проверяет поведение, а не устройство. Обращение — через публичную границу единицы. Тест, знающий о приватных полях и порядке внутренних вызовов, ломается при любом переписывании, которое ничего не изменило снаружи.

Тест независим. Порядок запуска не влияет на результат: каждый готовит своё состояние и убирает за собой. Тесты, работающие только в определённом порядке, скрывают ошибки и мешают параллельному запуску.

Отказ теста называет причину. Из сообщения должно быть понятно, что сломалось, без чтения кода теста. Проверка assert result менее полезна, чем проверка конкретного ожидаемого значения.

Один тест — одно утверждение о поведении. Не «проверить весь сценарий заказа», а «отказ при недостатке средств не создаёт заказ».

Ошибка сначала воспроизводится тестом. Тест, падающий до исправления и проходящий после, — это одновременно доказательство исправления и защита от повторения.

Внешние системы подменяются на своей границе. Подменяется клиент, а не сетевой вызов внутри него: тогда тест не зависит от того, какой библиотекой сделан запрос.


Данные для тестов

Состояние готовится самим тестом, а не общей базой, наполненной заранее: общий набор данных со временем становится непонятным, и никто не знает, что сломается при его правке.

Значения — осмысленные для проверки: если тест про отказ при недостатке средств, в нём видно, что средств не хватает. Случайные данные скрывают причину отказа.

Для тестов на связку хранилище поднимается на время прогона и удаляется после. Общая база на всех разработчиков даёт зависимость от порядка и от чужих данных.


Что проверять обязательно

Помимо основного пути:

  • границы входных данных: пусто, максимум, неверный тип, лишние поля;
  • отказы соседей: недоступное хранилище, таймаут внешней системы, ошибка очереди;
  • права: чужой ресурс не отдаётся и не изменяется — проверка на каждой ручке, а не на одной;
  • повторный вызов операций, которые обязаны быть идемпотентными;
  • форма ответа: конверт и коды ошибок — по ним ветвится фронт.

Проверка прав в тестах особенно важна: ошибка здесь не проявляется в обычной работе и обнаруживается только тем, кто ищет её намеренно.


Где лежат тесты

Рядом с кодом, который проверяют, — так они видны при чтении и не забываются при переносе. Сквозные тесты, требующие поднятой среды, — отдельным каталогом на уровне продукта.

Тесты переиспользуемой единицы принадлежат ей: потребитель не обязан проверять её работу.


Запуск

Один прогон одной командой, без ручных предварительных шагов. Результат — код возврата: ноль или нет. Прогон входит в сборку релиза; сборка при непрошедших тестах не выпускается.

Проверка:
<команда прогона>              # ожидается: все тесты прошли, код возврата 0
echo $?                        # ожидается: 0

Типичные отказы

ПризнакПричинаЧто делать
тесты падают через раззависимость от порядка или общего состояниякаждый тест готовит и убирает своё
после безобидного переписывания упало полсотни тестовтесты знают внутреннее устройствопроверять через публичную границу
набор перестали запускатьидёт слишком долгоперенести объём с сквозных на изолированные
тесты зелёные, на рабочей системе ошибкане покрыты стыки — схема, запросы, правадобавить тесты на связку с настоящим хранилищем
непонятно, что сломалосьпроверка без конкретного ожидаемого значениясравнивать с ожидаемым, а не проверять истинность
ошибка вернулась после исправленияне был написан воспроизводящий тестсначала тест, потом исправление
Инструкция не помогла?

Откройте исходник документа по ссылке «Предложить правку» — там же видно, что и когда в нём менялось.