CTS-KB

開発手法ガイド:テスト技法編 — レベル別・技法別の網羅戦略

⏱ 約 11 分で読めます
#開発手法 #テスト技法 #単体テスト #結合テスト #E2E #UAT #AI駆動開発

🤖 AI 駆動開発でテスト技法の体系が必要な理由

TDD 編 では 「いつテストを書くか」 を扱いました。本記事は 「何をどうテストするか」 — テストの体系 — を扱います。

AI が生成するコードは速く・量が多い。これを 網羅的に検証する ためには、 テストレベル × テスト技法 の体系を持っておく必要があります。

AI 駆動開発で起きる問題テスト技法が解決すること
AI が境界値で破綻する限界値分析・同値分割で系統的にカバー
AI が結合点で動かない結合テストで検出
AI が画面操作で詰まるE2E テストで検証
業務担当者の検収が通らないUAT 設計で先回り
カバレッジが上がるが実バグが残る「正しさ」を測るテスト設計

本記事は開発手法ガイド:概要のシリーズ 6 本目。TDD 編の直後に位置づけ、テストレベルと技法を 1 本で俯瞰します。

🏗️ テストレベル — 「どこをテストするか」

4 階層

テストは 対象範囲の大きさ で 4 つのレベルに分かれます。

レベル対象速度件数の目安代表ツール
単体テスト (Unit)関数・クラス単位数 ms数千〜Jest / Vitest / xUnit / pytest
結合テスト (Integration)モジュール間 / DB / API 連携数百 ms数百〜Testcontainers / Pact / MSW
システムテスト (E2E)アプリ全体(ブラウザ操作含む)数秒〜数十〜Playwright / Cypress / Selenium
受入テスト (UAT)業務担当者の検収人手シナリオ単位チェックシート / 受入仕様書

速度が下に行くほど遅く、件数も少なくなる — これが鉄則。AI 駆動開発では特に、 テストの実行速度がループ速度を決める ため、上位レベル(単体・結合)を厚く保つことが効きます。

テストピラミッド vs テストトロフィー

テストレベルの配分には 2 つの代表的な考え方があります。

テストピラミッド(Mike Cohn, 2009)とテストトロフィー(Kent C. Dodds, 2018)の比較。ピラミッドは単体テスト基盤型、トロフィーは結合テスト中心 + 静的解析基盤型。

モデル提唱者特徴
Testing PyramidMike Cohn (2009)単体テスト基盤型 — 単体多め・E2E 少なめ。バックエンド向き
Testing TrophyKent C. Dodds (2018)結合テスト中心型 — 静的解析を基盤に置き、結合を厚く。フロントエンド・型ありの言語向き

どちらを採るか

状況おすすめ
バックエンド(純粋ロジック多め)Pyramid
フロントエンド / API 連携多めTrophy
TypeScript / 型が厚い言語Trophy 寄り
AI 駆動開発で速度重視テスト実行が秒以内のレイヤーを厚く

🔬 テスト技法 — 「どう網羅するか」

テスト技法は大きく ブラックボックス (仕様ベース)と ホワイトボックス (コードベース)に分かれます。

ブラックボックステスト(仕様ベース)

入力と出力の関係 = 仕様に基づいてテストケースを設計します。

技法内容使いどころ
同値分割入力を等価なクラスに分け、各クラスから 1 件ずつテスト入力空間が広い
限界値分析同値クラスの境界を集中的にテストバグは境界に集まる
デシジョンテーブル条件の組み合わせを表にして網羅ビジネスルールが複雑
状態遷移テスト状態 + 入力 → 次の状態の組み合わせを網羅ワークフロー / Saga

限界値分析の具体例

「年齢が 18 以上 65 以下なら有効」という仕様:

同値分割:
  無効クラス1: 17 以下
  有効クラス:  18〜65
  無効クラス2: 66 以上

限界値:
  17, 18, 19, 64, 65, 66 を必ずテスト

バグはほぼ境界に集まる ため、限界値を確実にカバーすると検出率が劇的に上がります。AI に「網羅的にテストして」と任せると、限界値を忘れがちなので 「限界値分析と同値分割で」と明示 しましょう。

デシジョンテーブルの具体例

「会員ランク × 商品種別」で割引率が決まる場合:

会員ランク商品: 通常商品: セール
ゴールド10% 割引5% 割引
一般0%0%

4 ケース全てを必ずテスト 。条件が増えると組み合わせが指数的に増えるので、表で管理すると漏れない。

状態遷移テスト

注文の状態(受付 → 確定 → 出荷 → 完了)に対して、各遷移と「許可されない遷移」(出荷後に確定に戻すなど)を全網羅。 Saga パターンイベントソーシングを扱う領域で必須。

ホワイトボックステスト(コードベース)

ソースコードの構造に基づいてテストケースを設計します。 カバレッジ指標 とも対応します。

技法内容対応するカバレッジ指標
命令網羅 (C0)全ての文を 1 回以上実行Statement Coverage
分岐網羅 (C1)各 if の真偽両方を実行Branch Coverage
条件網羅 (C2)各条件式の真偽組み合わせを網羅Condition Coverage
経路網羅 (Path)全実行経路を網羅Path Coverage

例: if (a > 0 && b > 0) のテスト

技法必要なテストケース
命令網羅 (C0)a=1, b=1(true 経路)、a=0, b=0(false 経路)の 2 件
分岐網羅 (C1)上記 2 件で OK(分岐は真偽 2 種)
条件網羅 (C2)a=1/a=0 × b=1/b=0 の 4 件
経路網羅全実行経路 — 規模が大きいと組み合わせ爆発

通常は C1(分岐網羅) を最低基準に、複雑なロジックは C2 まで上げる、という運用。

MC/DC(Modified Condition/Decision Coverage)

航空・医療など 安全要件が厳しい領域 で求められる、各条件が独立して結果に影響することを示すカバレッジ。一般業務では不要ですが、 「条件網羅より厳格な指標がある」 という認識は持っておくと役立ちます。

その他のテスト技法

技法内容ツール例
探索的テストテスト計画なしに、感覚で穴を探す人間の経験
プロパティベーステスト入力をランダム生成、性質を検証QuickCheck / fast-check
性能テスト負荷・ストレス・ボトルネック特定k6 / Gatling / JMeter
セキュリティテストOWASP Top 10、ペネトレーションテストOWASP ZAP / Burp Suite
アクセシビリティテストWCAG 準拠確認axe-core / Lighthouse

🎭 テストダブル — 依存を分離する道具

単体テスト・結合テストでは、外部依存(DB・API・時刻・乱数)を テストダブル に差し替えるのが定石。

5 種類のテストダブル

種類役割
Stub決め打ちの値を返すだけgetUser() が常に固定ユーザーを返す
Mock呼び出された事実を 検証するsave が 1 回呼ばれた」を assert
Spy呼び出しを記録するだけ(事後検証)テスト後に「何回呼ばれたか」を見る
Fake簡易実装(インメモリ DB 等)InMemoryRepository
Dummy引数を埋めるためだけのオブジェクトnull 代わりの空クラス

Mock vs Spy の違い

Mock(事前期待):
  expect(repo).toHaveBeenCalledWith(order)  // 期待を先に書く
  → 期待外の呼び出しがあれば即失敗

Spy(事後検証):
  // テスト本体
  expect(spy.callCount).toBe(1)            // 後から確認
  → 柔軟だが、検証漏れの危険あり

Fake が一番強い

観点Mock / StubFake
本物への忠実度低(事前にハードコード)高(簡易実装で振る舞う)
テストの保守性API が変わると全壊API が変わっても追従可能
速度速い速い
AI 駆動開発との相性

リポジトリパターンIOrderRepository を切り、 InMemoryOrderRepository を Fake として実装すれば、 DB 起動なしで業務ロジックを単体テスト可能 。AI ループが秒で回ります。

📊 カバレッジ — 何を測るか

カバレッジの種類

指標何を測るか
Statement Coverage (C0)各文を実行
Branch Coverage (C1)各分岐を実行
Condition Coverage (C2)各条件式の真偽
Function Coverage各関数を呼び出し
Line Coverage各行を実行

カバレッジの罠

カバレッジ 100% でもバグはある。カバレッジが上がるテスト ≠ 良いテスト。

カバレッジは 「コードのどこが実行されたか」 を測るだけで、 「正しい振る舞いか」 は測りません。

ありがちな失敗結果
カバレッジを目標化assert なしのテスト量産(実行はするが検証しない)
カバレッジ 100% で安心限界値・例外パスが抜けてもバグ発覚せず
カバレッジが下がるたびに無理に上げる重要でない箇所のテストが増える

健全な閾値

レベル推奨カバレッジ
単体テスト80%+(コアロジックは 95%+)
結合テスト60%+
E2E テストハッピーパスのみ網羅すれば十分

CI への組み込み

  • カバレッジ低下する PR は 自動却下 (Jest threshold / coverlet threshold)
  • 新規コードは カバレッジ閾値を厳しめ に(既存負債は段階的に)
  • 業務上重要な箇所 のカバレッジを別管理(タグ付け)

🇯 UAT(受入テスト) — 業務担当者との橋渡し

UAT の本質

UAT は 開発者ではなく業務担当者 が「業務として OK か」を判定するテスト。

  • 仕様通りでも、業務に合わなければ NG
  • 業務フローと矛盾するシステム挙動を検出
  • 「現場で使えるか」を確認する最後の関門

UAT を設計する 3 つの型

1. シナリオベース

業務フロー単位で受入条件を作る:

シナリオ: 注文受付 〜 決済完了まで
前提: ログイン済み・カートに商品あり
手順: 1) 配送先入力 2) 決済方法選択 3) 注文確定
結果: 確定メール受信、在庫が引き当てられている

2. ユーザーストーリー(Given / When / Then)

Given 在庫 5 個の商品がカートに入っている
When  数量を 6 個に変更しようとする
Then  「在庫不足」エラーが表示される

3. 受入条件チェックリスト

[ ] 注文確定後、在庫が即座に減る
[ ] 確定メールが 1 分以内に届く
[ ] キャンセル時に在庫が戻る
[ ] 決済失敗時に注文が確定しない

AI 駆動開発との接続

UAT は 要件定義時点で設計 すると効きます。 ステアリング駆動開発requirements.md受入テストシナリオ を書いておけば、AI に実装を任せても 「受入条件を満たすか」 を Given/When/Then で検証できます。

業務担当者から UAT シナリオを引き出すのも 要件定義の一部 。これは ビジネスケイパビリティ の理解と対になる活動です。

🎯 AI 駆動開発でのテスト戦略

どのレイヤーを AI に任せやすいか

レイヤーAI への任せやすさ理由
単体テスト入出力が明確、AI が網羅的に書ける
結合テスト設定が複雑、人間が骨組みを作る
E2E テストUI 変更で頻繁に壊れる、慎重な設計が必要
UAT×業務担当者の判断が必要

AI に渡すと効く指示テンプレート

レベル: 単体テスト
対象:   PriceCalculator.applyDiscount()
技法:   限界値分析 + 同値分割
網羅:   0 円 / 1 円 / 9999 円 / 10000 円 / 100 万円 / 負数 / 小数
ダブル: なし(純粋関数)
レベル: 結合テスト
対象:   OrderService → PostgresOrderRepository
技法:   Testcontainers で本物の PostgreSQL 起動
網羅:   注文確定 / 重複注文の排他 / トランザクション失敗時のロールバック

よくある失敗

失敗是正
カバレッジ 100% を目標化「業務上重要な箇所」を別タグで管理。100% より 80% + 重要箇所 100%
単体だけで安心結合点(DB / API)で破綻するため、結合テストを必須化
E2E だけで担保実行が遅く AI ループが回らない。単体・結合を厚く
モック過剰「テストは通るが本物では壊れる」状態に。Fake を優先、境界だけ Mock
ハッピーパスばかり「限界値・例外パスを必ずカバーして」と AI に明示

⚠️ アンチパターン

1. テストレベルの偏り

単体だけ厚い → 結合点で破綻。E2E だけ厚い → 実行が遅く AI ループが回らない。

是正: テストピラミッド or トロフィーを 意識して配分 。AI 駆動開発では「秒で回るレイヤーを厚く」が鉄則。

2. 限界値・境界値を忘れる

AI に「テスト書いて」だけだと、ハッピーパスばかり書かれる。

是正: 「限界値分析と同値分割で網羅して」と明示。境界値リストを人間が事前に渡す。

3. デシジョンテーブルなしに条件分岐をテスト

条件の組み合わせが増えると、テスト漏れが指数的に増える。

是正: ビジネスルールは デシジョンテーブルで網羅性を担保 。表を AI に渡してテスト生成させる。

4. UAT を最後に押し付ける

リリース直前に業務担当者にチェックしてもらい、根本的な認識ずれが発覚 → 大量手戻り。

是正: UAT シナリオを 要件定義時点で作成 。ステアリングの requirements.md に受入条件を書く。

5. テストの実行が遅い

AI ループが回らない、CI が長い、開発体験が悪化。

是正: 単体は 数 ms 、結合は並列化、E2E はハッピーパスのみ。CI も並列実行で高速化。

6. テストダブルが「Mock 一辺倒」

API 変更で全テストが壊れる、メンテナンスコスト爆発。

是正: Fake を優先 。境界(DB / 外部 API)だけ Mock。 リポジトリパターン でドメイン層を Fake で単体テスト。

📚 まとめ

  • テストは レベル(縦軸) × 技法(横軸) で考える
  • レベル: 単体 → 結合 → E2E → UAT。 下に行くほど遅く、件数も減らす
  • 配分は Pyramid(古典)か Trophy(現代)。AI 駆動開発では 「秒で回るレイヤーを厚く」 が鉄則
  • ブラックボックス: 同値分割・限界値分析・デシジョンテーブル・状態遷移
  • ホワイトボックス: 命令網羅・分岐網羅・条件網羅 (カバレッジ指標と対応)
  • テストダブル 5 種を理解し、 Fake 優先・境界だけ Mock
  • カバレッジは 目的ではなく指標 。100% より「業務上重要な箇所」を確実に
  • UAT は 要件定義時点で設計requirements.md に Given/When/Then で書く
  • AI に任せやすいのは 単体テスト 。結合・E2E は人間が骨組み、UAT は業務担当者の判断

🔗 関連記事

📖 関連用語

テストレベル

  • 単体テスト — 関数・クラス単位の最小テスト
  • 結合テスト — モジュール間の連携を検証
  • E2E テスト — ユーザー操作でアプリ全体を検証
  • UAT — 業務担当者による受入テスト

テスト技法

テストダブル

配分モデル

設計と業務側

📎 参考資料