テスト戦略
プロジェクトのテスト種類、範囲、自動化レベルを体系的に定義する計画
テスト戦略とは
テスト戦略は、プロジェクトで実施するテストの種類、範囲、自動化レベル、実行タイミングを体系的に定義する計画である。「何をどのレベルでテストするか」を明確にし、品質とスピードのバランスを取る。
テストピラミッド
テストピラミッドは Mike Cohn が 2009 年の著書『Succeeding with Agile』で「テスト自動化ピラミッド」として示したモデルで、Martin Fowler の解説を通じて広く知られるようになった。下層ほど対象が狭く高速・安定・低コストで、上層ほど対象が広く低速・不安定・高コストになる。この非対称性があるため、同じバグを捕まえられるなら下層で捕まえるほうが得になる。
/ E2E テスト \ ← 少数、遅い、高コスト
/ 結合テスト \ ← 中程度
/ 単体テスト \ ← 多数、速い、低コスト
| レベル | 対象 | 速度 | 安定性 | 本数の目安 |
|---|---|---|---|---|
| 単体テスト | 関数、クラス | ミリ秒 | 高い | 70% |
| 結合テスト | モジュール間の連携 | 秒 | 中程度 | 20% |
| E2E テスト | ユーザーフロー全体 | 分 | 低い | 10% |
この 70/20/10 は Google Testing Blog の 2015 年 4 月の記事が「最初の当たりを付けるための目安」として挙げた分割で、普遍的な正解ではない。同記事も適切な比率はチームごとに異なると述べている。守るべきなのは数字そのものではなく、上に行くほど本数が減るピラミッド型を保つという形である。逆に E2E テストや手動テストが最も多い状態はアイスクリームコーンと呼ばれるアンチパターンになる。
各テストレベルの役割
単体テスト
// ビジネスロジックの正確性を検証
describe('calculateDiscount', () => {
it('10,000円以上で10%割引', () => {
expect(calculateDiscount(15000)).toBe(1500);
});
it('10,000円未満は割引なし', () => {
expect(calculateDiscount(5000)).toBe(0);
});
});
結合テスト
// Lambda ハンドラー + DynamoDB の連携を検証 (createOrder / getOrder は別ハンドラー)
it('注文を作成して取得できる', async () => {
const created = await createOrder({ body: JSON.stringify({ item: 'Book', qty: 1 }) });
expect(created.statusCode).toBe(201);
const orderId = JSON.parse(created.body).id;
const fetched = await getOrder({ pathParameters: { id: orderId } });
expect(fetched.statusCode).toBe(200);
expect(JSON.parse(fetched.body).item).toBe('Book');
});
E2E テスト
// Playwright でユーザーフロー全体を検証
test('商品を購入できる', async ({ page }) => {
await page.goto('/products');
await page.click('[data-testid="add-to-cart"]');
await page.click('[data-testid="checkout"]');
await expect(page.locator('.order-confirmation')).toBeVisible();
});
CI での実行戦略
テストレベルごとに実行時間が桁で違うため、同じジョブにまとめると速いテストの結果も遅いテストを待つことになる。レベルごとにジョブを分けて並列に走らせ、遅い E2E テストだけ実行の契機を絞ると、開発者が待つ時間を短く保てる。
# .github/workflows/test.yml (アクションのメジャー版は 2026 年 8 月時点)
on:
pull_request:
push:
branches: [main]
jobs:
unit-test: # 全 PR で実行 (数秒)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm ci
- run: npx vitest run
integration-test: # 全 PR で実行 (数分)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm ci
- run: npx vitest run --config vitest.integration.config.ts
e2e-test: # main への push だけで実行 (数分〜数十分)
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
- 単体テスト: 全 PR で実行。失敗したらマージをブロック
- 結合テスト: 全 PR で実行。外部依存はモックまたはローカル DB
- E2E テスト: main マージ時またはデプロイ前に実行
テスト戦略の判断基準
どのレベルを厚くするかは、プロダクトの性質で変わる。同じ対象を確かめる方法が複数あるとき、下の表の左右を読み比べて「そのレベルで確かめられることと確かめられないこと」を突き合わせると選びやすい。
| 判断基準 | 単体テストを増やす | E2E テストを増やす |
|---|---|---|
| ビジネスロジックが複雑 | 分岐と境界値を関数単位で網羅する | 経路が増えるだけで、条件の網羅には向かない |
| UI のインタラクションが重要 | 描画された後の操作までは確かめられない | 実際の操作順で確かめる。主要な導線に絞る |
| 外部サービスとの連携が多い | 通信部分を差し替えた結合テストで補う | 本物に繋ぐ経路を 1 本だけ通しておく |
| デプロイ頻度が高い | 数秒で結果が返り、1 日に何度でも回せる | 実行が長く、本数を増やすと出荷の足を引っ張る |
現場での応用を知るには関連書籍も役立つ。
この記事は役に立ちましたか?
関連用語
関連する記事
テスト本ガイド - テスト設計を学べる技術書の選び方
テストの書き方からテスト戦略まで学べる技術書の選び方を紹介。テストピラミッド、TDD の正しい読み方、テストの ROI の考え方を解説します。
「動くコード」と「良いコード」の間にある本
コードが動くようになった後、次に何を学べばよいのか。「動くコード」を「良いコード」に変えるために必要な知識と、それを効率的に学べる本の選び方を解説します。
バグを生むのは知識不足ではなく想像力不足である
バグの多くは、コードを書いた時点で「こういうケースもありうる」と想像できなかったことが原因です。想像力を鍛える読書法と、エッジケースへの感度を高める方法を解説します。