Claude Code × TDD——「テストが先、実装は後」をAIに守らせる3つのアプローチ

はじめに

「Claude Codeにテストも書かせているが、いつも実装の後にテストが来る」——これはClaudeのデフォルト動作による問題だ。

Claude Codeは何も言わなければ実装ファーストで動く。テストを依頼しても、内部では「どう実装するか」を考えながらテストを書くため、テストが実装の設計に合わせた形になる。これがコンテキスト汚染問題だ。

「テストが先」を守らせることで、テストが実装の設計図になり仕様のブレを防げる。バグを「作った瞬間」に検知できる。AIが自律的にテスト→実装→テストのループを回せるようになる。TDDの価値はAI時代でも変わらない。むしろ「AIが生成したコードの品質保証」として重要性が増している——「AIが書いたコードだから信用できない」という不安を、テストが解消する。AI駆動TDDでは、テストを「永続的な資産」ではなく「AIへの自律評価手段を与えること」として捉えると使いやすい。

なぜClaudeはTDDを守らないのか:コンテキスト汚染問題

TDDの本質は「実装を知らない状態でテストを書く」ことにある。ところが単一のコンテキストウィンドウで「テストを書いて→実装して」を依頼すると、構造的な問題が起きる。

テスト作成フェーズ

↓ この時点でClaudeは「どう実装するか」を考えている

テストが「実装案に最適化」された形で生成される

実装フェーズ

↓ テスト作成時の判断がそのまま引き継がれる

実装もテストも同じ前提から生まれ、整合性だけが確保される

実装の「抜け道」を許したテストが出来上がる

テストの役割は「実装の正しさを独立に検証すること」だが、同じコンテキストで生成されたテストはその独立性を失う。何も指示しなければ実装コードを書いてからテストを追加するし、「TDDで実装して」と言っても60〜80%のケースで先に実装が始まる(Hooks未使用時)。

アプローチ1:プロンプトでTDDを明示する(最もシンプル)

特別な設定なしに今すぐできる最初の一歩だ。

「TDDでテストだけ書いて。実装は書かない。モック実装も作らない。

テストを実行して落ちることを確認して」

「TDDで実装して」ではなく「テストだけ書いて」と明示することで先走りを防ぐ。より確実にするための4ステップのプロンプトシーケンスはこうなる。

Step 1(テスト作成):

「このAPIエンドポイントのテストだけを書いて。実装は書かない。

入出力の期待値を定義したら、テストを実行して失敗を確認して」

Step 2(テストコミット):

「テストが落ちることを確認した。今のテストをコミットして。

実装はまだ始めないで」

Step 3(実装):

「テストを一切変えないで、全てのテストが通るまで実装→テストを反復して」

Step 4(検証):

「この実装、テストに過剰適合してない?抜け道ない?

コード証拠なしの推測は禁止で、各指摘に確信度を付けて報告して」

プロンプトで効果を高める工夫:「t-wadaの推奨する進め方に従ってください」と指定するとTDDの実施率が大幅に向上することがわかっている(GMOペパボ2025年技術講演)。Claude Codeは学習データからt-wada氏のTDD実践知識を持っているため、権威ある方法論を参照させることで体系的なRed-Green-Refactorが実行される。

CLAUDE.mdへの記述でデフォルト化

## TDDルール

- 実装コードの前に必ずテストを書く

- テストが失敗することを確認してからコミット

- テストをコミットしてからセッションを分けて実装を行う

- 実装中はテストコードを変更しない

この記述があると、「実装して」という指示でもClaude Codeが自動的にテストファーストで動き始める。

アプローチ2:TDD Enforcer Skill

プロンプトに頼らず、Skillsファイルにワークフローそのものを定義してしまう方法だ。

# ~/.claude/skills/tdd-enforcer.md

機能リクエストのたびに以下の手順を必ず踏むこと:

1. 要件の明確化(何を実現するか・しないかを確認)

2. テストケースの先行生成(正常系・異常系・境界値を網羅し、失敗を確認)

3. テストカバレッジのレビュー(ユーザー承認を求める・ここで止める)

4. 実装コードの作成(ユーザー承認後のみ・テストを通す最小実装)

5. 全テスト通過の確認(新規テスト + 既存テストの両方)

6. 統合テストの生成

絶対NG:テストを書く前に実装コードを書くこと

このスキルを90日間運用したある個人エンジニアの実践報告(aihero.devによる参考値)では、本番バグ数70%削減(Sentry計測)、テストカバレッジ40%→90%、デバッグ速度50%高速化という結果が出ている。

アプローチ3:HooksによるRed-Green-Refactor完全自動化

最も強力な方法だ。SkillsはClaude Codeが従う「努力目標」だが、Hooksは「ルール違反時にシステムが止める」強制力を持つ。

TDD Guard(GitHub: nizos/tdd-guard)のアプローチでは、実装ファイルが作成・変更されるときに PreToolUse フックが発動し、対応するテストが事前に存在しなければ変更をブロックする。さらにサブエージェントを使った完全分離も実現できる。

[REDフェーズ] テスト作成サブエージェント

↓ 機能要件を受け取る・テストケースのみを生成

↓ テストが失敗することを確認してコミット

[GREENフェーズ] 実装サブエージェント(別コンテキスト)

↓ テストコードのみを受け取る(実装計画なし)

↓ テストを通す最小実装を作成

[REFACTORフェーズ] リファクタリングサブエージェント

↓ テストがgreenを保ちながら構造を改善

各フェーズが独立したコンテキストで動くため、REDフェーズの「実装アイデア」がGREENフェーズに流入しない。コンテキスト汚染を根本から防ぐ設計だ。

Hooksの設定が複雑に感じる場合、セッションを手動で分けるだけでも効果がある。

Session 1: 「TDDでテストだけ書いて。実装は書かない」→ テストをコミット → セッション終了(重要)

Session 2: 「このテストを全て通す実装を書いて」→ 実装をコミット

セッションを分けるだけで、テストと実装が「独立した視点」から生まれる効果がある。

ビフォーアフター

Before(TDDなし)

「この機能を実装して」と指示すると、Claudeが実装してから後でテストを追加する。テストが実装の形に合わせて書かれるため独立性はゼロで、本番でエッジケースのバグが発生して「なぜテストで検知できなかったのか」という状況になる。

After(TDD Enforcer Skill + セッション分離)

Session 1で「TDDでテストだけ書いて」→テスト作成→失敗確認→コミット。Session 2で「このテストを通す実装を書いて」→実装→テスト通過→コミット。テストが「実装を知らない視点」から書かれているため、エッジケースが実装ファーストより確実に網羅される。90日実測で本番バグ70%削減(aihero.devによる参考値)。

まとめ:今日からできること

難易度の低い順に並べてあるので、上から試してほしい。

1. 今すぐ(1分): 次の実装タスクで「TDDでテストだけ書いて。実装は書かない」を試す

2. 今日中: CLAUDE.mdに「実装コードの前に必ずテストを書く」ルールを追記する

3. 今週: ~/.claude/skills/tdd-enforcer.md にTDD Enforcer Skillを作成する

4. 本格運用: セッション分離パターン(テストコミット→新セッションで実装)を習慣化する

「AIが書いたから品質が低い」という不安を手放せるようになる——そのための仕組みがClaude Code × TDDだ。

コメント

タイトルとURLをコピーしました