テスト失敗の切り分け:実装・期待値・環境のどこが違うか

初級 | 13分 で読める | 2026.07.11

公式ドキュメント

テスト失敗のトリアージは、最初の失敗と再現条件を固定し、実装・期待値・テストコード・環境のどこに差があるかを切り分ける作業です。 テストが赤いからといって、実装だけが原因とは限りません。

なぜ必要か

失敗直後に期待値を実際値へ合わせると、不具合を正しい仕様として承認する危険があります。逆に、仕様変更後も古いテストを守るため実装を戻すと、新しい要求を失います。まず何が正しいかの根拠と、どの条件で失敗するかを確認します。

直す対象を決める前に、失敗が伝えている事実と期待仕様を分けます。

登場人物と対象

変更した実装者、テスト所有者、レビュー担当、CI・実行環境の担当、仕様を確認できる担当が関わります。対象には実装、アサーション、fixture、モック、DB、時刻、乱数、OS、ランタイム、依存、環境変数、実行順があります。

切り分けの全体像

最初の意味あるTest失敗を対象だけ同条件で再現し、仕様と照合して実装、期待値、Test構造、Data、環境へ原因候補を分け、対象から関連・全体へ確認を広げる図

切り分け順

  1. 最初の失敗メッセージを読む

  2. 対象テストだけを再実行する

  3. 毎回同じ結果か確認する

  4. 直前の実装・テスト・設定変更を見る

  5. 実際値と期待値のどちらが仕様に合うか確認する

  6. ローカルとCIのコマンド・バージョン・設定を比較する

  7. 原因を再現する最小テストを残して修正する

  8. 対象テストの後に関連テストと全体を実行する

最初に大量の失敗が出た場合、根本のセットアップエラー一件が後続失敗を起こすことがあります。出力末尾ではなく最初の意味ある失敗から読みます。

三つの候補

候補
実装計算結果やエラー処理が仕様と違う
テスト古い文言や順序を期待している
環境タイムゾーン、DB、環境変数が違う

実際にはテストコード・データの問題も分けると調査しやすくなります。

候補観察例次の確認
実装特定入力の実際値が仕様と違う関数・通信境界
期待値要求変更後も旧結果を期待Issue・仕様
テスト構造モックが実装詳細へ依存実際の契約
データfixtureが不足・共有セットアップと後片付け
環境CIだけ失敗バージョン・時刻・権限

分類は犯人探しではなく、次に比較する境界を選ぶために使います。

具体例

日付文字列のテストがCIだけ一日前になる場合、実装をすぐ補正せず、入力がUTCかローカル時刻か、CIのタイムゾーン、仕様がどの時刻基準を要求するかを確認します。順序が時々変わる配列なら、仕様で順序保証があるかを先に判断します。保証があるなら実装、ないなら順序を固定して期待するテストが誤りかもしれません。

不安定なテスト

再実行すると通るテストは放置しません。固定待ち時間、共有状態、実行順、外部通信への依存を確認します。

再実行を「直った証拠」にせず、何回中何回という観測と実行条件を残します。固定時間のsleepを増やすより、対象状態を待つ条件へ変えます。共有DBやグローバル状態は各テストで初期化し、並列実行の影響を確認します。

よくある誤解

ローカルで通ればCIが間違いとは限りません。CIはクリーン環境や異なる順序を通じて暗黙依存を見つけます。スナップショット更新も常に修正ではなく、差分が要求どおりかレビューが必要です。失敗テストをskipする場合は、期限と追跡Issueなしに放置しません。

注意とベストプラクティス

  • エラー全文と実行コマンド、対象コミットを記録する。
  • 秘密値をCIログへ出さない。
  • 失敗を再現する前にキャッシュや状態を無差別に削除しない。
  • 時刻・乱数・外部通信を制御可能にする。
  • 修正後に失敗理由を説明できる状態にする。

デバッグ・確認方法

対象テストだけ、同一ファイル、関連スイート、全体の順に広げます。繰り返し実行や順序変更で不安定性を確認し、ローカルとCIのランタイム・依存・環境変数名を比較します。差分を二分して原因コミットを探す場合も、共有ブランチの履歴を書き換えず安全な調査環境で行います。

修正後

失敗した理由を説明でき、同じ原因を再現するテストになっているか確認します。単に期待値を実際値へ合わせるだけでは、バグを承認する可能性があります。

実践演習:同じ失敗を三環境で比べる

失敗したテストについて、対象テスト単体、同じファイル全体、全スイートの順に実行し、結果と所要条件を記録します。単体では通り全体で落ちるなら、共有状態、実行順、並列性を優先して確認します。すべてで同じなら、実装・期待・fixtureの差へ進みます。

次にローカルとCIから、実行コマンド、Node.jsなどのランタイム、ロックファイルから入った依存、タイムゾーン、必要な環境変数名を比較します。秘密値は表示せず、存在と設定経路だけを確認します。OS固有のパス・改行・ファイル名大小文字も候補になります。

修正案を入れる前に、「この変更が正しければどの失敗がどう変わるか」を書きます。期待値更新なら仕様の根拠、実装修正なら回帰テスト、環境修正ならクリーン環境での再現を証拠にします。一度通っただけで完了せず、不安定性が疑われる場合は同条件で繰り返します。

優先順位を決める

複数の失敗がある時は、セットアップ、コンパイル、共有fixtureなど多くのテストへ波及する失敗を先に見ます。次に、認証・決済・データ損失など影響の大きい経路、最後に独立した表示差分というように、依存関係とリスクで並べます。単にログの件数が多い順にはしません。

既知の不安定テストが新しい失敗を隠している場合、隔離には追跡Issue、所有者、期限、代替確認を付けます。隔離を恒久的な成功扱いにせず、CI結果で除外件数が見える状態を保ちます。

トリアージ結果は、原因分類、影響範囲、暫定対応、恒久対応、確認したコマンドを短く残します。同じ失敗が再発した時に、過去の結論を盲信せず、今回の条件と比較する入口になります。

ケーススタディ:月末だけ失敗する期限判定テスト

提出期限の翌日を計算するテストが、月末のCIだけ失敗するとします。最初に実装へ一日を足す補正を入れるのではなく、入力時刻、タイムゾーン、日付処理、期待仕様を確認します。「翌日」が二十四時間後なのか、利用者の現地日付で次の日なのかによって正しい実装が変わるからです。

切り分けでは、失敗した入力を固定し、同じタイムゾーンで対象テストだけを再実行します。次に月中、月末、年末、夏時間切替の入力を比べます。月末だけなら境界計算、CIだけなら環境設定、実行順で変わるなら共有された時刻モックを疑います。良い記録は、入力、期待、実際、タイムゾーン、ランタイム、再現回数がそろいます。悪い記録は「日付テストがたまに落ちる」だけで、条件を再現できません。

修正を止める条件は、仕様の時刻基準を決める担当が不明、実データへの影響範囲を確認できない、テスト中に現在時刻を固定できない場合です。推測でUTCへ統一すると、利用者の締切日を変える危険があります。まず仕様を明確にし、時刻を注入できる境界を作り、失敗入力を回帰テストとして残します。

良い修正は、日付の目的を表す関数へ時刻基準を明示し、月末と年末のテストを追加し、ローカルとCIで同じ結果を確認することです。悪い修正は、期待値を現在の実際値へ更新する、再実行回数を増やす、月末だけテストを除外することです。原因を消さず、利用者に近い境界条件だけを監視対象から外します。

修正後は対象テストを複数回通すだけでなく、期限表示、通知、保存形式のテストへ範囲を広げます。失敗前の実装へ戻した時に追加テストが赤くなれば、回帰を捕捉する証拠になります。成功率だけでなく、固定条件で再現しなくなり、仕様の時刻基準をテスト名と期待値から説明できることを完了条件にします。

まとめ

テスト失敗では、最初の失敗、再現性、仕様の根拠、環境差を確認し、実装・期待・テスト構造・データ・環境へ候補を分けます。 修正後は原因を再現するテストを残し、対象から全体へ確認範囲を広げます。

参考リソース

次に読む記事

← 一覧に戻る
PR
PR
PR
PR