【比較】単体テスト・結合テスト・E2Eテストの違い¶
概要¶
「単体テスト(Unit Test)」「結合テスト(Integration Test)」「E2Eテスト(End-to-End Test)」は、自動テストを「どこまでの範囲を、どれだけ隔離して検証するか」で区別したものです。単体テストは1つの関数やクラスといった狭い範囲のロジックを、依存先を切り離して高速に検証します。結合テストは複数のモジュールや、データベース・外部APIといった実依存との境界(シリアライズ/通信)を検証します。E2Eテストはユーザーやクライアントから見た一連の流れを、システム全体を実際に動かして検証します。
この3つは「テストピラミッド」という指針で語られることが多く、Mike Cohn が著書『Succeeding with Agile』で提唱し、Martin Fowler らが整理しました。本記事では、Fowler の "The Practical Test Pyramid" と "Test Double" を一次情報として、範囲・速度・隔離・フィードバックの観点で正確に区別します。
例えるなら:自動車の検査¶
単体テストは「ボルト1本のトルクを測る」検査、結合テストは「ブレーキとペダルを繋いで踏み心地を確認する」検査、E2Eテストは「完成車をテストコースで実際に走らせる」検査に近いものです。完成車の試走は最も「本当に動くか」の確信を与えますが、遅く・高コストで、不具合が出ても原因箇所の特定が難しい。だからボルト単位の検査を大量に、試走を少数に、というバランスになります。
詳細比較¶
| 項目 | 単体テスト (Unit) | 結合テスト (Integration) | E2Eテスト (End-to-End) |
|---|---|---|---|
| 検証範囲 | 1関数〜1クラスなど狭い単位のロジック | 複数モジュール間/DB・FS・外部APIとの境界 | UI/API を入口にしたシステム全体の一連の流れ |
| 依存の扱い | テストダブル(モック/スタブ等)で原則隔離(solitary)。協調する依存を実物で使う流儀(sociable)もある | DB やメッセージキュー等を実物で動かし、シリアライズ/デシリアライズの境界を検証 | 本物のサービス群を起動し、極力モックしない |
| 速度 | 非常に高速(ミリ秒オーダー、数千件を秒で実行可) | 中程度(実依存の起動・I/Oで遅くなる) | 低速(ブラウザ起動・ネットワーク・複数サービス連携) |
| 不安定さ(flaky) | 低い(決定的になりやすい) | 中(外部状態・タイミング依存) | 高い。Fowler も「予期できない理由で頻繁に失敗しがち(notoriously flaky)」と指摘 |
| 失敗時の原因特定 | 容易(壊れた箇所がほぼ自明) | やや困難(どの境界かを切り分け要) | 困難(広い範囲のどこが原因か追跡が必要) |
| 得られる確信 | ロジックが正しいという確信 | モジュール/外部システムと正しく繋がる確信 | 「ソフトが実際に動く」最大の確信 |
| 保守コスト | 低い | 中 | 高い(壊れやすく書き換え頻度も高い) |
| ピラミッド上の量 | 多数(土台) | ある程度 | ごく少数(頂点) |
テストピラミッドの核となる主張は2つです。「粒度の異なるテストを書くこと」と「高レベル(広範囲)になるほどテストの数は少なくすべきこと」。Fowler の言葉では "Write lots of small and fast unit tests. Write some more coarse-grained tests and very few high-level tests that test your application from end to end." とまとめられます。
「単体テスト」の単位は言語により幅があり、オブジェクト指向言語では1メソッド〜1クラス程度を指します。依存を全てスタブ化して完全隔離する流儀を solitary(孤立的)、遅い/副作用のある協調オブジェクトだけ差し替えて実物も使う流儀を sociable(社交的)と呼びます。どちらを取るかは流派の問題で、どちらかだけが正解ではありません。
よくある誤解¶
-
「カバレッジ100%ならバグはない」は誤り。 コードカバレッジは「テスト実行時に通過した行/分岐の割合」を測るだけで、その結果が正しいかを検証したかは保証しません。表明(アサーション)が弱ければ全行通過でもバグは残ります。境界値・異常系・並行性・仕様誤りはカバレッジ数値に現れません。100%は「最低限ここは通した」であって「バグゼロ」ではありません。
-
「E2Eを厚くすれば単体テストはいらない」は誤り(アイスクリームコーン・アンチパターン)。 ピラミッドを上下反転させ、遅く壊れやすいE2Eに依存し単体テストが薄い状態は典型的なアンチパターンです。E2Eは確信は大きい一方で遅く・flaky で・失敗時の原因特定が難しいため、これだけに頼るとスイートが信頼されなくなります。土台の単体テストを多く、E2Eを少なく保つのが指針です。
-
「モックとスタブは同じ」は誤り。 Gerard Meszaros の分類(Fowler が紹介)では、スタブ(Stub)は「呼び出しに対して用意した固定の答えを返す」もので状態検証に使い、モック(Mock)は「期待する呼び出しの仕様を事前にプログラムされ、検証時に期待通り呼ばれたかをチェックする」振る舞い検証用です。さらに Fake は「動く実装を持つが本番には不適(例:インメモリDB)」と、別物として区別されます。「テストダブル」が総称で、その下位にこれらがあります。
実務での選び分け¶
- ロジックの正しさを素早く確かめたい/TDDの内側ループ → 単体テスト。高速で原因特定が容易なので最も多く書く。
- DB・外部API・メッセージング等との接続部や境界(シリアライズ)を検証したい → 結合テスト。実依存をコンテナ等で起動して確認する。
- 「ユーザー操作で重要シナリオが端から端まで通るか」のリグレッション防止 → E2Eテストを主要シナリオに絞って少数だけ用意する。網羅はしない。
- テストが遅い/不安定(flaky)で信頼されない → ピラミッド形に近づける。高レベルテストを減らし、同じ確認を下位レベルへ「押し下げ」られないか検討する。
ひとことまとめ¶
単体=隔離した狭いロジックを大量・高速に、結合=実依存との境界を中量で、E2E=システム全体の主要シナリオをごく少数で、というピラミッド型の配分が、確信・速度・保守コストのバランスを最適化します。
出典・参考¶
- The Practical Test Pyramid — Martin Fowler — ピラミッドの起源(Mike Cohn)、各層の定義、solitary/sociable、E2Eの flaky 性とアイスクリームコーン
- TestDouble — Martin Fowler (Gerard Meszaros の分類) — Dummy/Fake/Stub/Spy/Mock の正確な定義とモックとスタブの違い
- UnitTest — Martin Fowler — 「単体」の単位と solitary/sociable の流儀
- TestCoverage — Martin Fowler — カバレッジ数値の意味と限界(高い値≠バグゼロ)