Нестабильные (flaky) тесты создают постоянные трудности для тестировщиков. Такие тесты не отражают состояния тестируемой системы и подрывают доверие к тестовому набору.
Вооружившись лучшими практиками, нестабильность можно свести к минимуму, но полностью избавиться от неё крайне трудно. Чтобы лучше её контролировать, нужны инструменты, позволяющие выявлять нестабильные тесты — например, Allure Report. В этом руководстве мы посмотрим, как Allure работает с нестабильными тестами:
Исследуем, как устроена история тестов
Разберёмся, как история позволяет определять нестабильные тесты
Настроим перезапуск тестов
Эту функциональность мы рассмотрим на примере PyTest, но все те же принципы работают и с другими фреймворками.
Заодно мы познакомимся с Allure 3. Многие из вас наверняка пользуются Allure 2 — в третьей версии (помимо прочих изменений) работа с нестабильными тестами стала гораздо удобнее, в особенности настройка истории тестов.
1. Подготовка
Код демонстрации
https://github.com/rattus-aristarchus/guide-allure-reruns
Список зависимостей
Установка
Перед началом работы нужно установить:
Затем необходимо создать новый проект Python или открыть существующий.
В файл зависимостей (requirements.txt) добавим следующее:
pytest==9.0.2
allure-pytest==2.15.3Установим зависимости:
pip install -r requirements.txt2. Пробные тесты
Чтобы было на чём продемонстрировать возможности Allure, нам понадобится один нестабильный тест — и, для контраста, один стабильный:
import random
def test_stable():
"""
Стабильный тест
"""
assert 1 == 1
def test_flaky():
"""
Нестабильный тест: орёл — проходит, решка — не проходит
"""
assert random.randint(0, 1) == 1
Поместим их в файл test/flaky_test.py.
3. История тестов в Allure Report
Для обнаружения нестабильных тестов Allure нужна история прошлых запусков. Эта история хранится в специальном файле .jsonl.
Если Allure запускается на CI-сервере (например, Jenkins или GitHub Actions), история генерируется автоматически с помощью соответствующих плагинов. В ТестОпс — централизованной платформе на основе Allure — для работы с историей дополнительная настройка не требуется.
При локальном запуске Allure 2 история требовала много ручной работы; в Allure 3 она была автоматизирована, и теперь достаточно указать путь к файлу истории в настройках.
Создадим файл настроек allurerc.mjs в корне проекта:
export default {
// Имя отчёта
name: "Работа с нестабильными тестами",
// Путь к папке с отчётом
output: "./allure-report",
// Путь к файлу с историей тестов
historyPath: "./history.jsonl",
// Плагины
plugins: {
// awesome - базовый плагин для Allure 3
awesome: {
options: {
reportLanguage: "ru",
},
},
},
};
Архитектура Allure 3 построена на плагинах; базовая функциональность инструмента содержится в плагине awesome.
Убедимся, что история заработала; для этого выполним тесты.
Тесты и генерация отчёта (а также создание файла истории) в Allure 3 выполняются одной командой: npx allure run -- <команда_запуска_тестов>.
В нашем случае команда выглядит так:
npx allure run --config=./allurerc.mjs -- "pytest --alluredir allure-results"В флаге --config для allure run указываем путь к файлу конфигурации.
Выполним команду несколько раз, чтобы появилась история. В файле history.jsonl должно возникнуть несколько новых элементов — по одному на каждый запуск:

Чтобы посмотреть отчёт, выполним allure open:

Кликнем имя теста (например, test_flaky), и перейдём на вкладку История:

Как видим, история работает и прошлые запуски отображаются.
4. Определение нестабильных тестов
Allure определяет, что тест нестабилен, одним из двух способов:
Получает информацию от фреймворка (так, например, в JUnit 5). Этот случай сейчас мы рассматривать не будем, потому что он не автоматический.
Автоматически на основе истории запусков.
Во втором случае критерии нестабильного теста такие:
Тест падал как минимум один раз за последние 5 запусков.
После падения тест хотя бы один раз проходил успешно.
В текущем запуске у теста статус Неуспешный или Сломанный.
Тесты, подходящие под критерии, можно легко определить на вкладке Результаты по специальному значку:

При желании можно отфильтровать дерево тестов, чтобы оно отображало только нестабильные тесты:

К этой функциональности Allure можно добавить инструмент, запускающий тесты в случайном порядке — например, плагин для PyTest pytest-random-order. Результаты тестов не должны зависеть от выполнения других тестов, поэтому это хорошая проверка на стабильность.
5. Повторы (Retries)
Итак, мы нашли «моргающий» тест; что с ним делать?
В идеале нужно проанализировать причины нестабильности и исправить тест. Это требует времени и внимания. Сейчас в этом могут помочь нейросети — но поработать всё равно придётся.
Тест можно вручную поместить в «карантин» — добавить в коде аннотацию @pytest.mark.xfail. Но так мы не решаем проблему, а откладываем в долгий ящик: неработающие тесты будут копиться, пока рано или поздно, когда контекст уже давно выветрился из памяти, их снова придётся разгребать.
Наконец, тест часто перезапускают, чтобы исключить ложные падения. Allure 3 позволяет делать это «из коробки».
Для этого к команде запуска тестов достаточно добавить флаг --rerun с аргументом максимального количества перезапусков:
npx allure run --config=.\allurerc.mjs --rerun 3 -- "pytest --alluredir allure-results"Итоговый отчёт будет выглядеть так:

Как видите, наш test_flaky помечен двумя стрелками — это означает, что тест был перезапущен. Если щёлкнуть по тесту, на вкладке Перезапуски можно посмотреть подробную информацию о сбоях:

6. Заключение
Нестабильные тесты — известная проблема, и индустрия разработала множество инструментов для борьбы с ней. Allure 3 позволяет:
Легко настроить отображение истории запусков тестов
Автоматически обнаруживать нестабильные тесты
Перезапускать упавшие тесты
Про Allure 3 можно писать много — благодаря модульной архитектуре у него огромное пространство для экспериментов, и у нас наверняка будут ещё поводы поговорить о нём.
