# Нестабильные тесты Bazel {#bazel-flaky-tests}

> [!IMPORTANT]
> **Требования**
>
> - <.localized_link href="/guides/features/test-insights/bazel">Аналитика тестов Bazel</.localized_link>, настроенная через `tuist bazel setup`.

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


## Как работает обнаружение нестабильности {#how-it-works}

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

### Повторные запуски тестов {#test-retries}

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

```sh
tuist bazel test -- --flaky_test_attempts=3 //app:tests
```

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

### Обнаружение между запусками {#cross-run-detection}

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

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

Тест-кейсы определяются по метке цели, имени класса (с откатом к имени набора) и имени теста, как описано в разделе <.localized_link href="/guides/features/test-insights/bazel">Аналитика тестов Bazel</.localized_link>.

## Управление нестабильными тестами {#managing-flaky-tests}

### Автоматическая очистка {#automatic-clearing}

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

### Ручное управление {#manual-management}

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


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

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

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


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

```sh
tuist bazel test -- //app:tests
```

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

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

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

### Пропустить {#skip}

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

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

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

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


### Повторный запуск тестов из карантина {#running-quarantined-tests-again}

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

```sh
tuist bazel test --no-quarantine -- --nocache_test_results //app:tests
```

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

### Ограничения {#limitations}

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

Подробнее о базовом поведении см. в документации Bazel: [фильтры тестов](https://bazel.build/docs/user-manual#test-filter), [параметры командной строки](https://bazel.build/reference/command-line-reference) и [описания событий сборки](https://bazel.build/remote/bep-glossary).

## Уведомления в Slack {#slack-notifications}

Получайте уведомления, когда тест становится нестабильным, настроив <.localized_link href="/guides/integrations/slack#flaky-test-alerts">оповещения о нестабильных тестах</.localized_link> в вашей интеграции со Slack.


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

### CLI {#querying-cli}

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

```sh
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 {#querying-rest-api}

Те же данные доступны по HTTP. См. [эндпоинты тест-кейсов](https://tuist.dev/api/docs#tag/test-cases) в справочнике 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`.

