Autotests Guide
Цель данного гайда - зафиксировать используемую терминологию, прояснить какие типы автотестов мы используем, сколько и как их пишем
Общий подход
Наш подход весьма похож на тот, что использует Spotify но некоторые детали и термины разнятся.
Автотесты мы подразделяем на три группы:
- End-to-end tests
- Component tests
- Unit and Integration tests
End-to-end тесты
Тестируют корректность совместной работы нескольких сервисов. Сама система при этом считается черным ящиком.
В качестве входной точки используется GUI или публичное API.
Тестовые сценарии максимально близки к реальным пользовательским действиям, но такие тесты довольно ломкие. Большое влияние на их стабильность оказывают:
- инфраструктура
- задержки при асинхронных взаимодействиях
- внешние зависимости
- данные лежащие в сервисах
End-to-end тесты располагаем в отдельных репозиториях
Их написанием занимаются QA инженеры
TBD добавить ссылку на страницу посвященную деталям реализации e2e тестов в Ensi
Компонентные (сomponent) тесты
Тестируем сервис как отдельную изолированную единицу.
Используем так называемые In-process component тесты, которые размещаются в том же репозитории что и код и пишутся бэкэнд-разработчиками.
Типичный компонентный тест представляет собой следующее:
- Обеспечиваем необходимое состояние БД через фабрики моделей;
- Подменяем внешние зависимости вроде клиентов других сервисов Ensi на тестовые дубли, конфигурируем их ответы;
- Отправляем запрос в api/запускаем консольную команду/посылаем сообщение в потребитель очереди через внутренний роутер фреймворка чтобы ускорить тесты;
- Проверяем формат запроса и ответа на соответствие OpenApi спецификации для данного эндпоинта. Для Laravel эта проверка уже встроена через пакет в методы отправляющие http запросы в тестах;
- Проверяем ответ на корректность;
- Опционально проверяем, что в БД/файловом хранилище произошли нужные изменения. БД используем реальную, файловое хранилище используем локальное через
Storage::fake
;
В качестве фреймворка для написания таких тестов используем PEST, тесты располагаем не в tests/ а непосредственно рядом с компонентами, которые они тестируют
Для каждого эндпоинта API должен быть хотя бы один компонентный тест.
Компонентные тесты на нашем стэке довольно просты в написании, стабильны, быстры и при этом они дают уверенность, что при изменении кодовой базы сервиса его публичный интерфейс остается работоспособным.
Запуск компонентных тестов должен быть встроен в:
- CI/CD для сервиса, если тесты не прошли, то билд должен быть помечен как FAILED
- набор локальных git-хуков, включенных по умолчанию
Юнит (unit) и интеграционные (integration) тесты
Тестирование пограничных случаев через компонентные тесты может становиться затруднительным и многословным или приводит к избыточному дублированию. В этом случае вместо компонентных тестов нам на помощь приходят юнит тесты и интеграционные тесты, позволяющие протестировать более конкретный участок кода.
В этих тестах мы тестируем уже конкретный класс или его публичный метод, а не эндпоинт апи или консольную команду.
Если взаимодействуем и проверяем при этом БД/файловое хранилище/внешний сервис, то считаем такой тест интеграционным. Если нет - юнит тестом.
Хорошими индикаторами того, что вам необходимо покрыть метод (функцию/класс) unit/integration тестами являются:
- Внутри метода происходят сложные вычисления, особенно если они зависят от входных параметров;
- Метод используется в коде сервиса больше одного раза;
- Бизнес-логика содержащаяся в методе является ключевой для сервиса;
Если вы покрыли такие сценарии юнит тестами, то покрывать их все поверх еще и компонентными смысла нет. Стоит ограничиться там лишь самыми базовыми.
В качестве фреймворка для написания таких тестов используем PEST, тесты располагаем не в tests/ а непосредственно рядом с классами/функциями, которые они тестируют
Запуск тестов должен быть встроен в:
- CI/CD для сервиса, если тесты не прошли, то билд должен быть помечен как FAILED
- набор локальных git-хуков, включенных по умолчанию
Code Coverage
В расчёте code coverage (т.е процента строк кода покрытых хотя бы одним тестом) принимают участие component, integration и unit тесты. Мы не гонимся за 100% code coverage, в большинстве случаев это непрагматично. Чем ближе к 100% тем дороже в написании становится каждый новый процент и тем меньше от него реальной ценности.
В качестве ориентиров используем гайдлайны Google
60% - приемлимо
75% - похвально
90% - образцово
Проверка на минимальный code coverage должна быть встроена в CI. Если итоговый code coverage для ветки меньше 60%, то такой билд должен быть помечен как UNSTABLE или FAILED вовсе.