Xcode の不安定なテスト
- Xcode テストインサイト が設定されていること。Tuist は、各テスト実行でアップロードされたテストインサイトのイベントから不安定なテストを検出します。
不安定なテストとは、同じコードで複数回実行した際に異なる結果(合格または不合格)を生み出すテストのことです。これらはテストスイートへの信頼を損ない、誤った失敗の調査に開発者の時間を浪費させます。Tuist は不安定なテストを自動的に検出し、経時的な追跡をサポートします。

不安定な検出の仕組み#
Tuist は以下の 2 つの方法で不安定なテストを検出します。
テストのリトライ#
リトライ機能を使ってテストを実行すると、Tuist は各試行の結果を分析します。一部の試行では失敗し、他の試行では成功するテストは、不安定としてマークされます。
-retry-tests-on-failure または -test-iterations を tuist xcodebuild test に渡します。
tuist xcodebuild test \
-scheme MyScheme \
-retry-tests-on-failure \
-test-iterations 3

クロスラン検出#
テストのリトライがなくても、Tuist は同じコミット、スキーム、報告された宛先(デバイス名、プラットフォーム、OS バージョン)における異なる CI 実行の結果を比較することで、不安定なテストを検出できます。一致する CI 実行の 1 つでテストが成功し、別の実行で失敗した場合、その失敗した実行は不安定としてマークされます。この処理は、どちらの結果が先に到着しても機能します。
同じテストでも、スキームや宛先によって一貫して異なる動作をする場合があります。たとえば、iOS 26 で合格し iOS 27 で不合格になっても、それは不安定性を示すものではありません。異なるスキーム、デバイス、プラットフォーム、または OS バージョンからの結果同士は、互いを不安定としてフラグ付けしません。
宛先メタデータがない実行、または複数の宛先を対象とする実行は、互いとのみ比較されるため、それらの間での環境の違いは依然として不安定として報告される可能性があります。リトライベースの検出も引き続き適用されます。
これは、リトライで捕捉できるほど一貫して失敗しないものの、依然として断続的な CI の失敗を引き起こす不安定なテストを検出するために特に役立ちます。
不安定なテストの管理#
自動クリア#
検出とクリアはプロジェクト上の 自動化アラート を介して実行されます。すべてのプロジェクトにはデフォルトで「不安定なテスト検出」自動化が設定されており、その トリガー はテストを不安定としてマークし、リカバリー はテストが再トリガーされずに設定されたリカバリー期間(デフォルト 14 日)を経過するとフラグを解除します。設定 → 自動化 で編集して、リカバリー期間を変更したり、リカバリーアクション(例:テストの隔離も解除する)を変更したり、リカバリーを完全に無効にしてテストを手動でクリアするまで不安定なままにしておくことができます。
手動管理#
テストケースの詳細ページから、テストを不安定として手動でマークまたはマーク解除することもできます。これは以下のような場合に役立ちます。
- 修正作業中に既知の不安定なテストを認識したい場合
- インフラストラクチャの問題によりテストが誤ってフラグ付けされた場合
不安定なテストの隔離#
不安定なテストを隔離することで、修正中にCIがブロックされるのを防ぎます。デフォルトでは手動操作です。ダッシュボードのテストケース詳細ページから、テストを隔離したり、隔離を解除したり、モードを切り替えます。Settings → Automationsで自動化アラートを設定し、不安定さが閾値を超えたときにテストを自動的にミュート(またはスキップ)し、回復したら隔離を解除することもできます。手動および自動のすべての遷移は、テストケースの監査ログに記録されます。
デフォルトでは、トリガー条件が満たされなくなるまで回復を待つため、古い不安定な実行がトリガーウィンドウから外れるまでテストは隔離されたままになります。より早く回復させるには、Recover whenをNo new flaky runsに設定します。これにより、回復ウィンドウ(日数または実行回数)の間に新しい不安定な実行が発生しなければテストは回復し、新しい不安定な実行が発生するたびに待機時間がリセットされます。回復後は、新しい不安定な実行が発生した場合のみ再度隔離されます。
隔離されたテストは、次の 2 つのモードのいずれかになります。
- ミュート: テストは引き続き実行されますが、
tuist xcodebuild testが失敗をマスクします。失敗は依然として不安定なテストの検出器にフィードされるため、ビルドを壊すことなくテストを監視し続けることができます。積極的に調査中のテストにはこれを選択してください。 - スキップ: xcodebuild は
-skip-testing <identifier>を受け取るため、テストは開始されません。新しい結果は生成されず、再度有効にするまで不安定なテストのダッシュボードから除外されます。テストが壊れている場合、遅い場合、またはあまりにも持続的に不安定で実行することが CI の時間を無駄にする場合にこれを選択してください。
隔離されたテストが合格として表示される理由#
- ミュートされたテストは引き続き実行されます。失敗したミュートテストは、テストケースの実行で失敗として記録され、不安定としてフラグが立てられます。テストごとのステータスは書き換えられません。上書きされるのはテスト実行全体です。実行内の失敗しているテストケースがすべてミュートされている場合、実行全体は合格として報告されるため、ミュートされた失敗によってCIが中断されることはありません。
- スキップされたテストはまったく実行されないため、ダッシュボードにはそのテストの最後の実際の実行時のステータスが引き続き表示されます。そのスナップショットは数週間前のものかもしれません。
テストの実行#
tuist xcodebuild test は両方のモードを自動的に尊重するパススルーラッパーです。xcodebuild を呼び出すのと同じ方法で使用します。
tuist xcodebuild test -scheme MyScheme
スキップされたテストは -skip-testing <identifier> として xcodebuild の呼び出しに追加され、決して開始されません。ミュートされたテストは通常通り実行されます。失敗した場合、その失敗は結果のビルドステータスでマスクされます。
隔離のバイパス#
tuist xcodebuild test は --skip-quarantine を受け付け、ミュートおよびスキップされたテストを含めてすべてを実行します。
tuist xcodebuild test --skip-quarantine -scheme MyScheme
xcodebuild を直接呼び出す#
tuist xcodebuild test を経由できない場合は、tuist test case list を使用して隔離されたテストを -skip-testing 引数に自分で展開します。
xcodebuild test \
-scheme MyScheme \
$(tuist test case list --quarantined --skip-testing)
これは tuist xcodebuild test の外部での安全なデフォルトです。ミュートされたテストの失敗マスキングはそのコマンドを経由した場合のみ発生するため、両方のモードをスキップすることで誤った CI の失敗を回避できます。より細かい制御が必要な場合は、代わりに tuist xcodebuild test を経由してください。
新しいテストのストレステスト#
ストレステストゲートは、ブランチが追加したテストケースをそれぞれ新しいプロセスで複数回再実行し、不安定な結果となったものを報告します。新たに発生した不安定なテストは、それを導入したプルリクエスト上で確認でき、数週間後まで気づかないことはありません。
テストケースは、プロジェクトのデフォルトブランチで過去 90 日間 CI で実行されていない場合、またはそれ以降にそのブランチにマージされたコミットで実行されていない場合に新規とみなされます。マージキューを使用する場合、キューが実行したテストケースは、キューのコミットがマージされると認識され、キューがそれを削除した場合でも新規のままとなります。コミットは、Tuist が CI で収集する Git の履歴 を通じて照合されます。
有効にする#
ゲートはデフォルトでオフです。モードを設定してください:
report:不安定なテストケースごとに警告を表示します。実行はその結果に基づいて終了します。enforce:不安定なテストケースが実行を失敗させ、失敗したテストと同じ終了コードを返します。
report を数週間使用して、enforce が何をブロックしていたかを確認してください。
これをパススルー引数の前に渡すか、TUIST_TEST_STRESS_NEW_TESTS を設定して CI レーンごとにモードを変更します。
tuist xcodebuild test --stress-new-tests report -scheme MyScheme
各テストの再実行回数#
最初のパスでのテストケースの実行時間によって異なります。
| 最初のパス | 再実行回数 |
|---|---|
| 5秒以内 | 10 |
| 10秒以内 | 5 |
| 30秒以内 | 3 |
| 5分以内 | 2 |
| 5分超 | 再実行なし |
最初の到達した方の制限(200テストケースまたは10分)でパスが停止し、どの制限に達したかが表示されます。
再実行では、最初のパスでビルドされたものが再利用されます。
ゲートが実行されない場合#
- 最初のパスですでに失敗しています。まずそれらのテストを修正してください。
- プロジェクトにデフォルトブランチがないか、CI でまだ何も実行されていません。
- プロジェクトのテストケースの 30% 以上が新しいように見えます。これほど多くを再実行すると、コストに見合わない時間がかかります。Tuist へのレポートを始めたばかりのプロジェクトや、一度に多くのテストを移動させるリネームを行った後では、この状況が想定されます。
Slack通知#
Slack連携で不安定なテストのアラートを設定し、テストが不安定になった際に通知を受け取りましょう。
不安定および隔離状態のクエリ#
CLI#
tuist test case コマンドツリーは、Tuist がテストケースについて追跡するすべての情報を公開します。
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 リファレンスの テストケースエンドポイント を参照してください。テストケースの状態(不安定のマークまたは解除、ミュート、スキップ)を変更するには、is_flaky または state を指定して PATCH /api/projects/{account_handle}/{project_handle}/tests/test-cases/{test_case_id} を送信してください。同じ変更は tuist test case update および update_test_case MCP ツールとしても利用できます。