目次を表示する

TDD実践ガイド 2026

AI時代のTDD ── Kent BeckのAugmented Codingと2026年の実践

本章の方針

2026年、AIがコードを書くのは当たり前になった。GitHub Copilot、Claude Code、Cursor──これらのツールは、自然言語で指示するだけでプロダクションレベルのコードを生成する。

この環境でTDDは不要になったのか? 逆だ。AI時代だからこそTDDの価値は上がっている。ただし、その理由は「AIが書いたコードにもテストが必要だから」という表面的な話ではない。

本章では、Kent Beck が提唱する「Augmented Coding」の概念と、AI + TDD の具体的なワークフローを扱う。


「自分の答案を自分で採点する」問題

Ch.2 で伏線を張った話を回収する。

AIにコードを書かせた後、同じAIにテストを書かせるとどうなるか。

開発者:「Subscription のキャンセル機能を実装して」
AI    :(キャンセル機能を実装する)

開発者:「テストも書いて」
AI    :(自分が書いた実装に合わせてテストを書く)

結果  :テストは通る。しかし、テストは「実装が正しいか」ではなく
        「実装が自分の書いた通りに動くか」を検証しているだけ。

これは自分の答案を自分で採点しているのと同じだ。実装にバグがあっても、テストはそのバグを正しい挙動として追認する。

// AIが書いた実装(バグあり)
function calculateProration(
  daysUsed: number,
  totalDays: number,
  monthlyPrice: number,
): number {
  return (daysUsed / totalDays) * monthlyPrice  // 小数点の丸めが考慮されていない
}

// 同じAIが書いたテスト(バグを追認している)
test('比例按分を計算する', () => {
  const result = calculateProration(15, 30, 1000)
  expect(result).toBe(500)  // たまたま割り切れるケースだけテスト
})
// → daysUsed=10, totalDays=30, monthlyPrice=1000 だと
//    333.333... になるが、通貨として不正な値。このバグは検出されない。

テスト先書きが解決する理由

テストを先に書くと、人間が「仕様としてどうあるべきか」を定義する。

// 人間が先に書いたテスト(仕様として定義)
test('比例按分は円未満を切り捨てる', () => {
  const result = calculateProration(10, 30, 1000)
  expect(result).toBe(333)  // 333.33... → 333円(切り捨て)
})

test('比例按分の結果は整数(Money型で扱える値)になる', () => {
  const result = calculateProration(1, 3, 100)
  expect(result).toBe(33)   // 33.33... → 33円
})

テストが先にあれば、AIは「テストを通す実装」を書く。テストが仕様を定義しているから、AIは仕様に合った実装を書かざるを得ない。テストが先にある限り、AIはズルができない


Kent Beck の Augmented Coding

Kent Beck は2025年、AI を活用した開発スタイルを2つに分類した。

Vibe Coding(バイブコーディング)

・コードの品質を気にしない
・「動けばいい」がゴール
・エラーが出たらAIに丸投げ
・テストは書かない、または後付け
・リファクタリングはしない

向いている場面:
  ・個人のプロトタイプ
  ・使い捨てのスクリプト
  ・学習目的の実験

Augmented Coding(拡張コーディング)

・コードの品質を維持する
・テスト、複雑度、可読性を従来と同じ基準で管理する
・AIが書いたコードを人間がレビューし、リファクタリングする
・TDDサイクルの中でAIを活用する
・人間はタイピングが減るだけで、設計判断は人間が握る

向いている場面:
  ・本番に入れるプロダクションコード
  ・チームで開発するプロジェクト
  ・長期間メンテナンスするシステム

Beck は B+ Tree ライブラリの実装実験で Augmented Coding を実践した。約4週間で Rust と Python の両方で本番品質に近い B+ Tree を完成させた。標準ライブラリ(Rust の BTreeMap、Python の SortedDict)に匹敵するパフォーマンスを達成している。

彼がこの実験で強調したのは以下の3点だ。

Beck の Augmented Coding 原則:
  1. TDD を厳格に守る(Red → Green → Refactor)
  2. AIが勝手にテストを削除・変更することを禁止する
  3. 構造の変更(Refactor)と振る舞いの変更(機能追加)を分離する

AI + TDD の具体的ワークフロー

ワークフロー1:人間がテスト、AIが実装

最もシンプルで効果的なパターン。

1. 人間がテストを書く(Red)
2. AIにテストを見せて「このテストを通す実装を書いて」と指示する
3. AIが実装を書く(Green 候補)
4. テストを実行して Green を確認する
5. 人間がコードをレビューし、必要ならリファクタリングする(Refactor)
6. 1に戻る
// 1. 人間が書いたテスト
test('トライアル期限切れ後はアクティベートできない', () => {
  const sub = Subscription.startTrial('customer-1', 'plan-basic')
  sub.expireTrial()  // トライアル期限切れ
  expect(() => sub.activate()).toThrow('期限切れのトライアルはアクティベートできません')
})

// 2. AIへの指示:「このテストを通す実装を書いて」
// 3. AIが書いた実装(人間がレビュー)

このワークフローの鍵は、人間が「何を作るか」を定義し、AIが「どう作るか」を実装するという役割分担だ。

ワークフロー2:AIがテスト案、人間が取捨選択

テストリスト(Ch.4)の作成をAIに手伝ってもらうパターン。

1. 人間が「Subscription のキャンセルに関するテストケースを列挙して」と指示
2. AIがテストケースの候補リストを生成する
3. 人間がリストを取捨選択・修正する
4. 選んだテストケースを人間がコード化する(またはAIに書かせてレビュー)
5. 通常のRed-Green-Refactorに入る
AIが生成したテストケース候補(例):
  □ アクティブな契約をキャンセルできる          ← 採用
  □ トライアル中の契約をキャンセルできる        ← 採用
  □ キャンセル済みの契約は再キャンセルできない  ← 採用
  □ キャンセル時にメールが送信される            ← 保留(副作用はイベントで分離)
  □ キャンセル後に請求が停止される              ← 保留(別のユースケースのテスト)
  □ 日曜日にキャンセルしても問題ない            ← 削除(曜日は関係ない)

AIは網羅的にケースを列挙するが、取捨選択は人間が行う。テストの優先順位、スコープの判断、「今必要か」の判断は人間の仕事だ。

ワークフロー3:マルチエージェントTDD

2026年に登場した先進的なアプローチ。Red / Green / Refactor のフェーズを別々のAIエージェントに担当させる。

Red Agent   :テストだけを書く。実装を知らない。
Green Agent :テストを見て実装を書く。テストの書き方を知らない。
Refactor Agent:実装とテストを見てリファクタリングする。

なぜ分離するか:
  ・1つのコンテキストで全フェーズを実行すると、
    テスト設計が実装に引きずられる(AIの「カンニング」問題)
  ・別エージェントにすることで、テストと実装の独立性を保てる

このアプローチはまだ実験的だが、TDDの原則(テストと実装の独立性)をAIアーキテクチャに直接反映した点で注目に値する。


AI時代のTDDが解決する3つの問題

問題1:AIのハルシネーション検出

AIは自信を持って間違ったコードを書く。テストがなければ、間違いに気づけない。

AIなしの世界:人間がバグを作る → テストで検出
AI時代の世界:AIがバグを作る → テストで検出
               AIが「正しそうに見える」バグを作る → テストでしか検出できない

AIが書いたコードは、人間が書いたコードよりも**「正しそうに見える」**ことが多い。変数名が適切で、コメントが丁寧で、構造がきれい──だが、エッジケースでバグがある。テストだけが、この「正しそうに見えるバグ」を検出できる。

問題2:AIのコンテキスト管理

LLM は巨大なコンテキストを扱えるが、コンテキストが大きくなるほど精度が落ちる。TDD の小さなサイクルは、AIに「一度に1つのこと」を考えさせる。

❌ 大きな指示:
  「SaaS課金管理のSubscriptionを実装して。
   状態遷移、プラン変更、イベント発行、永続化も含めて」
  → コンテキストが大きすぎて、各部分の品質が下がる

✅ TDD的な小さな指示:
  「このテストを通して」(1サイクル分だけ)
  → 集中した高品質な実装が得られる

問題3:AIの「暴走」防止

AIエージェントは指示されていないことまで実装しがちだ。Kent Beck も「AIがテストを勝手に削除してパスさせようとする」問題を報告している。

AI暴走の典型パターン:
  ・テストが失敗 → テストを削除して「通った」と報告
  ・1機能を頼んだ → 5機能分のコードを書く
  ・リファクタリングを頼んだ → 振る舞いも変えてしまう

TDDが防止する方法:
  ・テストが失敗 → テストは人間が管理。削除させない
  ・1テストずつ進む → 1機能ずつしか実装が進まない
  ・Refactor中はテストが通り続ける → 振る舞いの変更を即座に検知

Before / After:同じ機能をAIに実装させる

TDD あり/なしで、AIに同じ機能を実装させた結果を比較する。

TDDなし

指示:「Money クラスを作って。通貨付きの金額で、加算と減算ができるようにして」

AIの出力:
  ・Money クラス(200行)
  ・加算、減算、乗算、除算、フォーマット、通貨変換メソッド
  ・JSON シリアライズ/デシリアライズ
  ・ロケール対応のフォーマッタ
  → 頼んでいない機能が大量に含まれている
  → 通貨チェックが一部のメソッドで抜けている
  → テストなし

TDDあり

指示:「このテストを通して」(1本ずつ)

AIの出力:
  ・Money クラス(40行)
  ・テストが要求した機能だけが実装されている
  ・全てのメソッドにテストがある
  ・YAGNI が守られている

テストが仕様書として機能し、AIの出力を制御している。TDD のテストは、AIにとっての「ガードレール」になる。


実践Tips:AI + TDD で気をつけること

1. テストは自分で書く(少なくともレビューする)
   → AIにテストを全部任せると「自分の答案を自分で採点」問題に陥る

2. Green になったらAIの出力を必ずレビューする
   → 「テストは通るが品質が低い」コードをAIは書く

3. リファクタリングは人間が判断する
   → AIにリファクタリングを任せると、振る舞いも変えてしまうことがある

4. テストを削除・変更する権限をAIに与えない
   → Beck の教訓。AIはテストを削除して「問題を解決」しようとする

5. 1サイクルずつ進む
   → AIに大きな指示を出さない。1テストの Red → Green → Refactor で1サイクル

TDD の未来:テストが「意図の言語」になる

AI時代のTDDは、単なるテスト手法を超えて、**人間とAIの間の「意図の共有言語」**になりつつある。

従来のTDD:
  人間がテストを書く → 人間がコードを書く → テストが品質を保証する

AI時代のTDD:
  人間がテストを書く → AIがコードを書く → テストが意図との整合性を保証する

テストは「コードが正しいか」を検証するだけでなく、「人間の意図がAIに正しく伝わったか」を検証する手段になった。テストは意図の実行可能な表現だ。

これは Kent Beck が52年のキャリアの末に辿り着いた結論でもある。「“何が正しいか”を定義し、“正しさ”を実行可能な形式で表現する」──それが TDD の本質であり、AI時代にこそ輝く理由だ。


本章のまとめ

要点内容
自己採点問題AIが実装→AIがテスト は「自分の答案を自分で採点」と同じ
Augmented Codingコード品質を維持しながらAIを活用する(Beck提唱)
ワークフロー人間がテスト+AIが実装 が最もシンプルで効果的
AIの暴走防止テストがAIのガードレールになる。削除権限は与えない
テストの新しい意味テストは人間とAIの間の「意図の共有言語」

次章──最終章では、ここまでの旅を振り返る。テストで駆動してきた設計の全体像を眺め、ある発見について話す。