Надёжность сквозных тестов
Что это такое
Надёжность отличает набор сквозных тестов, на который команда полагается, от набора, который перезапускают, пока он не станет зелёным. Достигается она просто: каждый прогон начинается с известного состояния и заканчивается чистым, всякое ожидание ждёт условия, а не задержки, отказ оставляет достаточно улик для диагностики, а порядок тестов и машина значения не имеют — технической работы здесь немного, вся дисциплина в отказе принимать нестабильный тест за норму.
Почему это важно
Красная сборка, которая, скорее всего, ничего не значит, хуже отсутствия сборки: она приучает всех игнорировать сигнал, а ущерб накапливается — настоящие отказы пропускают, терпимость к нестабильности растёт, и в конце концов команда отключает конвейер, который должен был её защищать. Причину нестабильности сквозных тестов почти всегда можно назвать: общее состояние, событие, которого не дождались, зависимость от окружения, — а конкретную причину можно и исправить.
Ключевые идеи
Ждите условий, а не времени
Чаще всего нестабильность порождает фиксированная пауза, подставленная вместо неизвестного объёма работы. Ожидание условия и быстрее, и надёжнее: оно возвращается, как только состояние наступает, и падает с понятным сообщением, когда оно так и не наступило. Современные браузерные инструменты ждут автоматически для своих действий, однако любое состояние, которое создаёт ваш код, всё равно требует явной проверки, на которой можно ждать.
await expect(page.getByRole("status")).toHaveText("Saved"); // условие
await page.waitForTimeout(3000); // ставка наугад
Начинайте с чистого листа и оставляйте его чистым
Каждый прогон создаёт нужные ему аккаунты, записи и файлы с именами, уникальными для этого прогона, а затем убирает или оставляет их так, чтобы это не помешало новому прогону. Тесты, которые предполагают, что подготовленный пользователь уже существует, пройдут локально и упадут в конвейере — или наоборот: пройдут в конвейере и упадут, стоит кому-то изменить эти данные. Идентификатор прогона в каждой созданной записи делает очистку дешёвой, а отладку — проще.
id прогона: e2e-20260301-7f3a
каждое имя, созданное этим прогоном, содержит его
Прогоняйте одни и те же тесты против одной и той же сборки
Продвигайте одну сборку по средам, а не собирайте заново под каждую среду. Тест, который проходит против артефакта, действительно запускаемого в продакшене, даёт доказательство, тогда как тест против отдельно собранного почти такого же артефакта даёт лишь надежду. Данные, от которых зависят тесты, заморозьте, а часы зафиксируйте там, где проверка чувствительна ко времени.
Делайте отказы диагностируемыми
Когда тест падает в конце конвейера, уликами становится только то, что тест сохранил: снимок экрана, видео, трассировка, лог консоли, сетевые запросы. Настройте раннер собирать их при отказе и называйте артефакты по имени теста. Повторная попытка, которая ничего не сохраняет, хуже отказа: она уничтожает и улики.
при отказе: снимок экрана + трассировка + лог сервера, загружаются с id прогона
Считайте повторную попытку сообщением об ошибке
Повторные попытки уместны для по-настоящему недолговечной инфраструктуры, но если тест нуждается в ней дважды в неделю, у него есть невыявленная гонка. Отслеживайте частоту повторных попыток как любую другую метрику ошибок и уделяйте самому нестабильному тесту столько же внимания, сколько ошибке в продакшене. Иначе получится набор, зелёный цвет которого ничего не значит.
Практика
Уберите паузу
Найдите фиксированную задержку в сквозном тесте и замените её проверкой, которая ждёт появления нужного состояния.
Готово, когда: тест зелёный, измеримо быстрее и падает с понятным сообщением, когда ожидаемое состояние так и не наступает.
Докажите, что два прогона независимы
Прогоните весь набор сквозных тестов дважды подряд против одной среды, а затем ещё раз в перемешанном порядке.
Готово, когда: все три прогона дают одинаковый результат и ни один тест не зависит от данных, созданных другим.
Частые ошибки
- Фиксированная пауза для синхронизации — тест падает только на более медленных машинах, то есть именно там, где это важно; исправить: ждите условия с тайм-аутом.
- Зависимость от данных, созданных другим прогоном — набор проходит в одиночку и падает при параллельном запуске; исправить: создавайте уникальные имена данных для каждого прогона.
- Автоматический повтор без сбора улик — нестабильность скрыта и никогда не диагностируется; исправить: сохраняйте снимок экрана и трассировку при каждом отказе, повторялся он или нет.
- Отдельная сборка под каждую среду — тестируемая сборка не та, что развёрнута; исправить: продвигайте один артефакт по средам.
- Принятие заведомо нестабильного теста — сигнал набора угасает, а настоящие отказы игнорируются; исправить: почините его или удалите и никогда не оставляйте в карантине бессрочно.
Что читать дальше
- Управление системой как пользователь (01-cs-fundamentals/26-end-to-end-testing/01-driving-the-system-like-a-user) — пути, которые защищают эти привычки, поэтому читайте его первым.
- Интеграционное тестирование (01-cs-fundamentals/21-integration-testing) — перенос медленной нестабильной проверки на уровень ниже, где она может быть детерминированной.
- Отладка (01-cs-fundamentals/11-debugging) — системный подход к отказу, который случается только иногда.