フロントエンドのテスト方針はプロダクトの状況に応じて定めるべきという話
概要
フロントエンドのテスト方針はプロダクトの状況に応じて決めるのが良いと思っているので、このことについて雑に書いてみたいと思います。理想形としては、Kent C. Dodds が示した Testing Trophy(静的・ユニット・インテグレーション・E2E の層を定義し、インテグレーションテストを厚めにする考え方)に寄せたいです。ただし現場にはプロダクトのフェーズやチームの事情があるため、Testing Trophy を土台にしつつ配分を調整するのが現実的だと考えています。
たとえば、すでにリリース済みなのに自動テストがほとんど無い場合は、まず主要導線だけを確認する最小限の E2E テストを 1〜3 本用意し、その安全網のもとでリファクタを進めながらインテグレーション/ユニットテストを少しずつ増やす、という順番が取りやすいと思います。
用語の定義(Testing Trophy に合わせて)
先に、この記事で使う用語を Testing Trophy の分類に合わせて簡潔にそろえます。
- 
静的解析(Static)
 型チェックやリンタなど、コードを実行せずにバグの芽を摘む層です。Testing Trophy では土台に位置づけられます。
- 
ユニットテスト(Unit)
 単体の関数やモジュールの振る舞いを確認するテストです。外部依存を切り離し、入力に対して期待した出力かを見ます。
- 
インテグレーションテスト(Integration)
 複数の部品がつながったときの振る舞いを確認するテストです。UI コンポーネントと状態管理、API モックと表示更新など、ユーザーの操作で結果が更新されるかに焦点を当てます。Testing Trophy ではここを最も厚く持つことが推奨されています。
- 
E2E テスト(End-to-End)
 ブラウザなどを使って、ユーザーの一連の操作(ユーザーフロー)を本番に近い形で確認するテストです。数は少なめにし、主要な導線だけを押さえるのが Testing Trophy の考え方です。
- 
ビジュアルリグレッションテスト(VRT)
 見た目の変化を画像の差分で検出するテストです。DOM が同じでもスタイルが崩れていないかを確認します。こちらも Testing Trophy の枠外ですが、デザイン品質が重要なときに補助的に使うのは有効です。
なぜ「プロダクトの状況に応じて定めるべき」なのか?
まず、プロダクトの状況ごとに最適なテスト配分が変わるからです。段階(立ち上げ/成長期/保守が難しくなった状態)、領域のリスク(決済・医療・公共など)、変更頻度、画面の複雑さ、チームの人数や経験、技術的負債の量——これらの組み合わせで「どこが壊れると一番困るか」と「どこなら少ない手間で守れるか」は変わります。だから、全チーム一律の決まりきったやり方ではなく、状況に合わせて効くところから順に積むのが現実的だと思います。
次に、既存コードの構造や依存関係が取り組み順序を左右するからです。結合が強い実装に対して最初からユニットテストを増やすと、実装詳細に縛られた壊れやすいテストになりがちです。一方、まず主要導線だけを E2E テストで押さえると「大きくは壊れていない」という広い安心を先に確保でき、そこから安全にリファクタし、インテグレーション → ユニットテストの順で細かくしていけます。
さらに、限られた時間と人数で最大の効果を得るには、ユーザーに近い振る舞いを厚く守るのが効率的だからです。ここで役に立つ整理が Testing Trophy です。土台の静的解析で雑音を減らし、インテグレーションテストを主役に据え、ユニットでロジックを支え、E2E テストは要所だけを短く押さえる——このバランスは、変更が多いフロントエンドと相性が良いと感じます。ただしこれは理想形なので、プロダクトの事情に合わせて Testing Trophy をベースに配分を調整します。
状況に応じた方針の具体例
リリース済みでテストがない場合
ログイン → 購入/申込など、主要導線だけを確認する最小限の E2E テストを 1〜3 本用意します。これでユーザーフローが途切れていないかを継続的に確かめられます。最初にユニットテストから増やさないのは、広い安心につながりにくく、実装詳細に縛られたテストがリファクタで壊れやすいからです。安全網を置いたら、インテグレーションテストを厚くし、計算や整形などはユニットテストで固めます。こうして Testing Trophy の順序に近づけていきます。
具体例(EC):まず「商品詳細 → カート → 購入完了」だけ E2E テストで通します。その後、検索フォーム →API モック → 結果表示 → ページングの一連をインテグレーションテストで押さえ、在庫引き当てや送料計算はユニットテストで境界値まで確認します。
テストはあるが不安定/遅い場合
目標は、テスト結果を素直に信頼できる状態に戻すことです。待ち時間に依存する処理や外部 API への依存が不安定さの原因になりがちなので、該当部分はモック/スタブに置き換えます。置き換え可能な E2E テストはインテグレーションテストへ移し、原因特定を速くします。
具体例(B2B SaaS ダッシュボード):外部分析サービスの制限が原因でレポート生成の E2E テストが失敗していました。そこでレポート API を固定レスポンスのモックに置き換え、可視化コンポーネントとのつながりはインテグレーションテストで確認するようにしました。これにより再現性が安定し、実行時間も大幅に短縮できます。
新規開発(ゼロから作る場合)
設計と同時にテストの責務分担を決めることが大事です。たとえば、静的解析 → ユニットテスト → インテグレーションテストを先に整え、重要なユーザーフローだけ少数の E2E テストで確認する構成にします。コンポーネントや状態の作りは、あとからテストしやすいように設計します(外部とのやり取りは差し替え可能にし、計算や判定は小さな関数に分けるなど)。こうしておくと、Testing Trophy の考え方(インテグレーションテストを厚め)を保ったまま、機能追加や仕様変更に対応しやすくなります。
具体例(社内ツール):承認フローは「申請 → 承認 → 履歴反映」を E2E で 1 本だけ持ち、一覧のフィルタや CSV 出力はインテグレーションテスト、金額や文字列整形はユニットテストで押さえます。
高リスク領域(決済/料金計算/認可など)
仕様逸脱が事故につながる領域は、多層で守ります。金額計算や付与ロジックはユニットテストで境界値まで、画面と API の連携はインテグレーションテストで、完了までのユーザーフローは短い E2E テストで確認します。Testing Trophy の比重を維持しつつ、要所の E2E テストだけ濃くするイメージです。
具体例(決済):割引とポイント併用時の金額計算はユニットテストで網羅します。決済画面 → 外部ゲートウェイの応答 → 結果表示はインテグレーション・テストで確認し、完了までの流れは E2E テストで 1 本だけ保持します。
デザインシステムや共通コンポーネント
Testing Trophy の外側の話ですが、見た目の破壊的変更を早期に検知したい場合は、Storybook などと組み合わせた ビジュアルリグレッションテスト(VRT) を補助的に使います。相互作用はインテグレーションテスト、ユーティリティはユニットテストで下支えするのが基本です。
具体例(デザインシステム):ボタン・モーダル・フォームの主要バリアントだけを VRT の対象にし、フォーム送信 → バリデーション → エラー表示はインテグレーションテストで確認します。
注意点
- E2E テストを増やしすぎない:対象は「ログイン → 購入完了」など重要なユーザーフローに絞ります。合計実行時間は 5 分以内を目安にし、クーポン有無や支払方法の違いのような分岐はインテグレーション/ユニットテストで確認します。
- 実装詳細に依存しない:DOM のクラス名や内部状態ではなく、画面上の結果を確認します。例:「商品名が表示されている」「ボタンを押すと確認ダイアログが開く」「合計金額が 3,300 円になっている」。
- スナップショットの乱用を避ける:ページ全体の出力比較は避け、守りたい出力(見出しの文言、エラーメッセージなど)だけに限定します。必要なら「要素が表示される」「リンク先が正しい」などの意図のある確認に置き換えます。
- 失敗したテストの責任を明確にする:例として「当番が一次対応する」「自分の変更で失敗したテストは当日中に直す」「直せない場合は一時的に無効化して課題を起票する」といったルールを決めます。
まとめ
理想は Testing Trophy に沿った配分です(静的解析を土台に、主にインテグレーションテストを厚くし、ユニットでロジックを支え、E2E は少数精鋭に絞ります)。ただし現場には制約があるので、プロダクトの状況に合わせて厚みを調整します。私はこのアプローチが、スピードと安心を両立させるうえで現実解だと考えています。
みなさんの現場での配分や運用の工夫、異なる視点などがあれば、ぜひコメントやフィードバックで教えてください!
参考資料



Discussion