テストピラミッド
単体テスト、結合テスト、E2E テストの比率を示すテスト戦略のモデル
テストピラミッドとは
テストピラミッドは、Mike Cohn が 2009 年の著書『Succeeding with Agile』で「テスト自動化ピラミッド」として示したテスト戦略のモデルで、下層 (単体テスト) を多く、上層 (E2E テスト) を少なくする。Martin Fowler の解説記事 (2012 年 5 月) を通じて広く知られるようになり、一般には短く「テストピラミッド」と呼ばれる。
この形が推奨される根拠は非対称性にある。下層ほど対象が狭いので高速 / 安定 / 低コストになり、上層ほど対象が広いので低速 / 不安定 / 高コストになる。同じ欠陥を捕まえられるなら下層で捕まえるほうが得になるため、下を厚くする。
ピラミッド
上に行くほど幅が狭くなる形が本体で、各層の実行時間と安定性は下から上へ向かって単調に悪化する。
/ E2E \ 少数、遅い、不安定
/ 結合テスト \
/ 単体テスト \ 多数、速い、安定
| レベル | 速度 | 安定性 | コスト | 本数の目安 |
|---|---|---|---|---|
| 単体テスト | 最速 | 高い | 低い | 70% |
| 結合テスト | 中程度 | 中程度 | 中程度 | 20% |
| E2E テスト | 遅い | 低い | 高い | 10% |
この 70/20/10 は Google Testing Blog の 2015 年 4 月の記事が「最初の当たりを付けるための目安」として挙げた分割で、モデルが規定する値ではない。同記事も適切な混ぜ方はチームごとに異なるとしており、保つべきなのは数字ではなく上に行くほど本数が減るという形である。自分たちの数字は、どの層で欠陥を捕まえられているかと、どの層に時間を取られているかを見て決める。
各レベルの役割
層の境目は「何を差し替えるか」で決まる。単体テストは対象の外側を差し替えることが多く、結合テストは自分たちのモジュール間だけを本物にし、E2E テストは何も差し替えず利用者と同じ入口から動かす。
| レベル | テスト対象 | ツール |
|---|---|---|
| 単体テスト | 関数、クラス、モジュール | Vitest |
| 結合テスト | モジュール間の連携、API | Vitest + supertest |
| E2E テスト | ユーザーフロー全体 | Playwright |
アンチパターン: アイスクリームコーンと砂時計
ピラミッドを上下反転させた形がアイスクリームコーン (逆ピラミッド) で、避けるべき形のアンチパターンとして知られている。
\──── 手動テスト ────/ ← 最も多い (遅い・高コスト)
\── E2E テスト ──/
\─ 結合テスト ─/
\ 単体テスト / ← 最も少ない
手動テストと E2E テストに依存し、単体テストが少ない状態。欠陥を見つける位置が実装から遠いので、失敗したときに原因の切り分けから始めることになり、修正までの時間が層の数だけ伸びる。不安定な失敗が混じるため、失敗を見ても再実行で済ませる習慣が付き、テストが警報として機能しなくなる。
Google Testing Blog の同記事はもう 1 つ、砂時計と呼ばれる形も挙げている。単体テストは多いが、結合テストで見るべき範囲を E2E テストで見てしまい、真ん中がくびれた状態である。モジュールをつなぐ部分の食い違いを、いちばん遅い層で検出していることになる。
対案: テスティングトロフィー
ピラミッドへの代表的な対案が、Kent C. Dodds が 2018 年 2 月に示したテスティングトロフィーである。層の順序は同じだが、幅が単調にならず、結合テストがいちばん厚くなる。
┌───────────┐
│ E2E │ 少数
┌──┴───────────┴──┐
│ 結合テスト │ ← 投資の中心
└──┬───────────┬──┘
│ 単体テスト │
┌──┴───────────┴──┐
│ 静的解析 │ 型検査・構文解析ツール
└─────────────────┘
この形は各層の投資に対する見返りを表したもので、対象は JavaScript のアプリケーションである。最下層に静的解析が加わっているのは、ピラミッドが生まれた頃の主要な言語と違い、JavaScript では型検査が前提として存在しないためだと Dodds 自身が説明している。同時に、この図がサービス間の構成に当てはまるかは検討していないとも述べている。つまりピラミッドと矛盾する主張というより、適用範囲を絞った別の見取り図である。
判断の目安としては、画面の部品を組み合わせて成り立つ層 (フロントエンド) では結合テストを厚くし、入力と出力が値で閉じる層 (計算 / 変換 / 判定) では単体テストを厚くする。どちらの図でも E2E テストが最少である点は変わらない。
Lambda のテスト戦略
関数単位で動く構成では、層を分ける境界を「ハンドラーの外側を本物にするか」に置くと迷わない。
| レベル | テスト内容 |
|---|---|
| 単体テスト | ビジネスロジック (純粋関数) |
| 結合テスト | Lambda ハンドラー + モック DB |
| E2E テスト | API Gateway → Lambda → DynamoDB (dev 環境) |
カバレッジの読み方
ピラミッドの各層を積んだ結果としてカバレッジは上がるが、カバレッジそのものを目標に据えると形が崩れる。E2E テストを 1 本増やせば通過行は一気に増えるので、数字を追うと上層が太る方向へ引っ張られる。
数字を見るときは 3 点に注意する。第 1 に、行が実行されたことと、その振る舞いが検証されたことは別である。返り値を確かめない呼び出しでも行は数えられる。第 2 に、行カバレッジと分岐カバレッジは別物で、条件の片側だけを通った状態でも行は埋まる。第 3 に、書かれていない仕様は測定の対象外なので、未実装の要求はカバレッジ 100% でも検出されない。
運用上の判断基準は、絶対値の目標より「下げない」こと。変更のあった範囲について、その変更で追加された分岐が検証されているかを見るほうが、全体の数字を大きく上げるより効く。
テストピラミッドの背景や設計思想は関連書籍に詳しい。
この記事は役に立ちましたか?
関連用語
関連する記事
テスト本ガイド - テスト設計を学べる技術書の選び方
テストの書き方からテスト戦略まで学べる技術書の選び方を紹介。テストピラミッド、TDD の正しい読み方、テストの ROI の考え方を解説します。
「動くコード」と「良いコード」の間にある本
コードが動くようになった後、次に何を学べばよいのか。「動くコード」を「良いコード」に変えるために必要な知識と、それを効率的に学べる本の選び方を解説します。
バグを生むのは知識不足ではなく想像力不足である
バグの多くは、コードを書いた時点で「こういうケースもありうる」と想像できなかったことが原因です。想像力を鍛える読書法と、エッジケースへの感度を高める方法を解説します。