Перейти к содержимому

Нестабильные тесты Bazel

Требования

Нестабильные тесты — это тесты, которые дают разные результаты (проходят или падают) при многократном запуске с одним и тем же кодом. Они подрывают доверие к набору тестов и отнимают время разработчиков на расследование ложных сбоев. Tuist автоматически обнаруживает нестабильные тесты и помогает отслеживать их со временем.

Как работает обнаружение нестабильности#

Tuist использует отдельные тест-кейсы из отчетов Bazel test.xml, чтобы выявлять несогласованные результаты при повторных запусках и при сравнении прогонов с тем же коммитом и выбором целей в непрерывной интеграции. Локальные запуски остаются видимыми, но не помечают тест-кейсы как нестабильные автоматически.

Повторные запуски тестов#

Повторные запуски необязательны и не зависят от карантина. Флаг --flaky_test_attempts=3 разрешает до трех попыток выполнения теста в Bazel всего, а не три дополнительных повтора. Сохраните существующую конфигуграфию повторов в .bazelrc или передайте её явно:

bash
tuist bazel test -- --flaky_test_attempts=3 //app:tests

Чтобы Tuist мог зафиксировать результаты, повторные запуски должны действительно выполняться. Сводка нестабильности цели Bazel сама по себе не определяет, какой именно тест-кейс был нестабильным.

Обнаружение между запусками#

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

bash
tuist bazel test -- \
--build_metadata=CI=true \
--build_metadata=GIT_COMMIT="$GIT_COMMIT" \
--build_metadata=GIT_BRANCH="$GIT_BRANCH" //app:tests

Тест-кейсы определяются по метке цели, имени класса (с откатом к имени набора) и имени теста, как описано в разделе Аналитика тестов Bazel.

Управление нестабильными тестами#

Автоматическая очистка#

Обнаружение и очистка выполняются через автоматизированное оповещение в проекте. Каждый проект получает автоматизацию «Обнаружение нестабильных тестов» по умолчанию, чей триггер помечает тест как нестабильный, а восстановление снимает флаг, когда тест проходит настроенный период восстановления (по умолчанию 14 дней) без повторного срабатывания. Отредактируйте её в разделе Настройки → Автоматизации, чтобы изменить период восстановления, действия при восстановлении (например, также вывести тест из карантина) или полностью отключить восстановление, чтобы тесты оставались помеченными как нестабильные, пока вы не снимете метку вручную.

Ручное управление#

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

  • Вы хотите подтвердить наличие известного нестабильного теста во время работы над исправлением
  • Тест был ошибочно помечен из-за проблем с инфраструктурой

Карантин нестабильных тестов#

Карантин изолирует нестабильный тест, чтобы он не блокировал CI, пока вы его исправляете. По умолчанию это ручное действие: вы помещаете тест в карантин, выводите его из карантина и переключаете режимы на странице деталей тест-кейса в дашборде. Вы также можете настроить автоматическое оповещение в разделе Settings → Automations, чтобы тест автоматически игнорировался (или пропускался) при превышении порога нестабильности и выводился из карантина после восстановления. Каждое изменение состояния, ручное или автоматическое, записывается в журнал аудита тест-кейса.

По умолчанию восстановление ожидает, пока условие срабатывания перестанет выполняться, поэтому тест остаётся в карантине, пока старые нестабильные запуски не выйдут за пределы окна триггера. Чтобы ускорить восстановление, установите для параметра Recover when значение No new flaky runs: тест восстановится, как только окно восстановления (в днях или запусках) пройдёт без новых нестабильных запусков; каждый новый нестабильный запуск перезапускает ожидание, а после восстановления только новый нестабильный запуск снова поместит тест в карантин.

Команда tuist bazel test получает политику карантина перед каждым вызовом и применяет её к базовому запуску bazel test. Обычный запуск bazel test по‑прежнему сообщает результаты тестов, но не применяет карантин:

bash
tuist bazel test -- //app:tests

Аргументы после -- передаются в bazel test. Используйте --path, чтобы выбрать проект и рабочий каталог, и --bazel, чтобы выбрать другой исполняемый файл, например bazelisk. Именованная конфигурация Bazel, такая как --config=ci, необязательна и работает аналогично.

Игнорировать сбои#

Используйте Игнорировать сбои как основной сценарий карантина. Игнорируемые кейсы продолжают выполняться, их сбои остаются видимыми, а работоспособные кейсы из того же набора всё ещё влияют на результат. Tuist преобразует код выхода Bazel при сбое теста в успешный только тогда, когда отчеты относят каждый сбой в каждой неуспешной цели к игнорируемому кейсу. Ошибки сборки, таймауты, прерванные запуски, отсутствующие или неполные отчеты, а также сбои вне множества игнорируемых кейсов сохраняют статус сбоя Bazel.

Пропуск работает на уровне цели Bazel: пропуск одного кейса исключает всю его цель, включая работоспособные кейсы, потому что Bazel не может фильтровать отдельные кейсы для каждого тестового фреймворка. Отдавайте предпочтение режиму Игнорировать сбои, если вы не хотите исключать цель целиком. Команда выводит метки всех исключенных целей, чтобы в логах сборки было видно, что осталось за рамками политики карантина.

Если пропущенная цель больше не существует, Tuist указывает её в предупреждении и выполняет запуск без этого исключения. Верните устаревшие кейсы в состояние Включено, чтобы навсегда удалить их политики. Если не осталось ни одной тестовой цели, Bazel сохраняет свой обычный статус выхода «тесты не найдены».

Почему карантинные тесты могут отображаться как пройденные#

  • Тесты с игнорированием сбоев всё равно выполняются. Если такой тест завершается ошибкой, это фиксируется как сбой в запуске тест-кейса и помечается как нестабильный; статус отдельного теста не перезаписывается. Переопределяется только общий результат запуска тестов: если все упавшие тест-кейсы в запуске находятся в режиме игнорирования сбоев, весь запуск считается успешным, поэтому такие сбои не ломают CI.
  • Пропущенные тесты вообще не выполняются, поэтому на панели управления продолжает отображаться статус последнего фактического выполнения теста. Эти данные могут быть устаревшими на несколько недель.

Повторный запуск тестов из карантина#

Чтобы исследовать проблему или проверить исправление, обойдите политику карантина:

bash
tuist bazel test --no-quarantine -- --nocache_test_results //app:tests

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

Ограничения#

  • Явные флаги --build_event_json_file и --target_pattern_file нельзя использовать вместе с активным карантином. Передавайте шаблоны целей напрямую.
  • Если Tuist не может получить политику карантина, команда останавливается до запуска тестов. Частичное применение политики никогда не выполняется. Используйте --no-quarantine, если вы намеренно хотите запустить тесты без карантина.
  • Сбой, совпадающий с правилом игнорирования, записанным под старым идентификатором на основе набора, остаётся блокирующим, и команда указывает политику, которую нужно применить повторно.

Подробнее о базовом поведении см. в документации Bazel: фильтры тестов, параметры командной строки и описания событий сборки.

Уведомления в Slack#

Получайте уведомления, когда тест становится нестабильным, настроив оповещения о нестабильных тестах в вашей интеграции со Slack.

Запрос состояния нестабильных и изолированных тестов#

CLI#

Дерево команд tuist test case предоставляет всю информацию, которую Tuist отслеживает о тест-кейсе:

bash
tuist test case list --flaky # only flaky test cases
tuist test case list --quarantined # only muted or skipped test cases
tuist test case show <test_case_id> # detail: flakiness rate, last status, run counts
tuist test case events <test_case_id> # audit log: marked_flaky, muted, skipped, ...
tuist test case run list <test_case_id> # run history with status and duration
tuist test case run show <test_case_run_id> # single run, including failure breakdown

Все эти команды поддерживают --json для использования в скриптах.

REST API#

Те же данные доступны по HTTP. См. эндпоинты тест-кейсов в справочнике API для получения полного списка маршрутов, фильтров и полей ответа. Чтобы изменить состояние тест-кейса (отметить или снять отметку о нестабильности, игнорировать, пропустить), отправьте PATCH /api/projects/{account_handle}/{project_handle}/tests/test-cases/{test_case_id} с параметром is_flaky или state. То же изменение доступно через команду tuist test case update и инструмент MCP update_test_case.