Почему интеграционному тестированию API нужен явный граф
| Порядок становится случайным | Тесты проходят в том порядке, который случайно выбрал тестовый раннер, и падают на другой машине. Кто-то добавляет плагин для сортировки тестов — и проблема закрепляется навсегда. |
| Один сбой выглядит как двадцать | Падает вызов создания — падает всё, что ниже по цепочке, и вы получаете экран, залитый красным. Основной работой становится поиск первого настоящего сбоя. |
| Параллельный запуск небезопасен | Не зная, что от чего зависит, вы не можете безопасно запускать что-либо одновременно. Поэтому наборы тестов остаются последовательными и медленными. |
Как сделать его явным
Решение в том, чтобы каждый тест объявлял, что ему нужно и что он производит. Как только это есть, раннер сам выводит безопасный порядок, независимые ветки идут параллельно, а при сбое зависящие от него тесты помечаются как пропущенные, а не как упавшие. Двадцать красных строк превращаются в один сбой и девятнадцать пропусков — а это совсем другой опыт отладки.
В этом и разница между Endpoint Tests, которые покрывают по одному маршруту за раз, и Integration Tests — многошаговыми цепочками, где один ответ становится входными данными для следующего шага.
Проблема передачи значений
Вызов создания возвращает идентификатор, который нужен следующим шагам. Зашьёте его в код — тест отработает ровно один раз. Захватите его — и цепочка будет корректно передавать данные дальше. На бумаге это звучит тривиально, но именно это самая частая причина, по которой набор тестов, проходивший месяц назад, падает сегодня.
Очистка внутри цепочки
Интеграционные тесты создают больше состояния, чем тесты отдельных эндпоинтов, и создают его в порядке зависимостей, который обязана учитывать процедура очистки. Нельзя удалить клиента раньше его заказа. Единственный вариант, который переживает параллельный запуск, — очистка, привязанная к тому, что создал конкретный прогон, и выполняемая в обратном порядке зависимостей.
Четыре вещи определяют, переживёт ли набор API-тестов свой первый год: истекающие сессии, значения, которые существуют только во время выполнения, вызовы, зависящие друг от друга, и записи, которые никто не удаляет. В TestSprite за это отвечают Auto-Authentication, Dynamic Variables, Dependency Chains и Auto-Cleanup, описанные в документации по тестированию API.
Что делать, когда цепочка падает на четвёртом шаге
Польза от явного объявления зависимостей лучше всего видна в том, как выглядит сбой, и стоит знать, в каком порядке его читать.
Сначала проверьте, где сбой: в самом шаге или в его входных данных. Шаг, получивший неверный идентификатор, упал потому, что что-то выше по цепочке выдало не то значение, и чинить сам шаг — значит лечить симптом.
Затем проверьте, падает ли он при запуске с чистого состояния. Цепочка, которая отрабатывает один раз и падает при повторном запуске, говорит о том, что очистка не сработала, — это уже другой баг, не тот, который вы ищете, и часто более важный.
И только третьим шагом смотрите на сам эндпоинт. Чаще всего всё интересное было в первых двух проверках — именно поэтому плоский список красных строк обходится в отладке гораздо дороже, чем граф с одним сбоем и девятнадцатью пропусками.
Держите цепочки короткими
Цепочку из двенадцати шагов, которая падает на девятом, трудно диагностировать и долго перезапускать. Полезный размер — три-пять шагов, покрывающих одно намерение пользователя. Длинные цепочки обычно означают, что в одну слились два сценария.
С чего начать
Терминал
npm install -g @testsprite/testsprite-cli
testsprite setup
Если вы предпочитаете ничего не устанавливать, то же самое можно сделать в дашборде. Всё остальное, что умеет командная строка, описано в репозитории CLI.
Подключите репозиторий в дашборде — и прогоны будут запускаться от того деплоя, который вы и так собираете, либо вместо этого добавьте отдельный шаг в свой собственный пайплайн.
Как TestSprite делает граф явным
Каждый тест-кейс объявляет, что ему нужно и что он производит, а Dependency Chains выводят из этого безопасный порядок выполнения. Независимые ветки выполняются параллельно, а когда что-то падает, зависящие от него кейсы помечаются как пропущенные, а не как упавшие, — и двадцать красных строк превращаются в один сбой и девятнадцать пропусков.
Передачу значений берут на себя Dynamic Variables: цепочка несёт идентификатор, который вернул вызов создания, а не число, которое кто-то вставил руками. Auto-Cleanup удаляет то, что создал каждый прогон, в обратном порядке зависимостей — именно это делает параллельные прогоны безопасными.
Выгода становится очевидной при первом же сломе цепочки. Вместо экрана красного, который приходится вычитывать, вы получаете один сбой, указывающий на место расхождения, — это разница между пятиминутной диагностикой и половиной рабочего дня.
Чем это отличается от end-to-end тестирования?
End-to-end обычно означает проверку через интерфейс. Интеграционное тестирование API проходит те же сценарии на уровне сервисов — это быстрее и точнее показывает, где именно произошёл сбой.
Должны ли интеграционные тесты использовать реальные зависимости?
Для интеграционного тестирования — да, в этом и смысл. Замокав то, с чем вы интегрируетесь, вы ответите на другой вопрос.
Как передавать тестовые данные между шагами?
Захватывайте то, что производит каждый шаг, и передавайте дальше. Общие предзаполненные данные удобны ровно до тех пор, пока две цепочки не обратятся к одной и той же записи.
Что делать со сторонними сервисами внутри цепочки?
Используйте их песочницу, если она есть. Если её нет, изолируйте этот шаг и примите, что у цепочки есть граница.
Сколько интеграционных тестов нужно?
По одному на каждый значимый пользовательский сценарий, а не на каждую комбинацию эндпоинтов. Комбинаций бесконечно много, сценариев — нет.
Объявите граф явно — или отлаживайте его вечно.
Интеграционное тестирование API — это про последовательности, а у последовательностей есть граф зависимостей. Когда каждый тест объявляет, что ему нужно и что он производит, вы получаете безопасный порядок, параллельность и читаемые сбои. Захватывайте значения вместо того, чтобы зашивать их в код, и держите цепочки короткими.