# 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` を指定すると、追加のリトライ 3 回ではなく、テストごとに **合計 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` などの異なる実行ファイルを選択します。`--config=ci` などの名前付き Bazel 構成はオプションで、同じように動作します。

### ミュート {#mute}

主要な隔離ワークフローとして **ミュート** を使用します。ミュートされたケースは引き続き実行され、その失敗は表示されたままになり、正常な兄弟ケースは結果に影響を与え続けます。Tuist は、失敗した各ターゲット内のすべての失敗がミュートされたケースに起因するとレポートが示す場合にのみ、Bazel のテスト失敗による終了コードを成功に変換します。ビルドエラー、タイムアウト、中断された実行、欠落または不完全なレポート、およびミュートセット外の失敗は、Bazel の失敗ステータスを維持します。

### スキップ {#skip}

スキップは Bazel ターゲット単位で動作します。1 つのケースをスキップすると、正常なケースを含め、そのターゲット全体が除外されます。これは、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}

Slack連携で<.localized_link href="/guides/integrations/slack#flaky-test-alerts">不安定なテストのアラート</.localized_link>を設定し、テストが不安定になった際に通知を受け取りましょう。


## 不安定および隔離状態のクエリ {#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 経由で利用できます。ルート、フィルター、レスポンスフィールドの完全なリストについては、API リファレンスの [テストケースエンドポイント](https://tuist.dev/api/docs#tag/test-cases) を参照してください。テストケースの状態（不安定のマークまたは解除、ミュート、スキップ）を変更するには、`is_flaky` または `state` を指定して `PATCH /api/projects/{account_handle}/{project_handle}/tests/test-cases/{test_case_id}` を送信してください。同じ変更は `tuist test case update` および `update_test_case` MCP ツールとしても利用できます。

