MF Blogs 便利ツール
Red-Green-Refactorの3つの円が時計回りに連なる抽象イラスト。赤・緑・青の3色で循環構造を示す

記事

Claude Codeでテスト駆動開発(TDD)を回す手順:Red-Green-Refactorの依頼テンプレート

Claude Codeでテスト駆動開発を回すための具体的な依頼文を、Red(失敗テスト先行)、Green(最小実装)、Refactor(テストを保ったまま整理)の3フェーズに分けてまとめます。バグ修正TDD、Plan Modeとの組み合わせ、AIに任せきってはいけない判断ポイントまでカバーします。

0:00 0:00

結論:Claude CodeはTDDと相性が良い。理由は「検証ループ」と「根拠ある修正」

Claude Codenpm testpytestを自分で実行できます。だからこそ、**「テストを書く → テストを通す → テストを保ったままリファクタする」**というTDDの3フェーズが、依頼文1本で回せる構造になっています。公式のBest Practicesも「Claudeに検証手段を与えることが最も効果が高い」と明言しており、テストはClaudeが自分で結果を見て直せる、最良の検証手段です。

本記事では次の3フェーズと、よくあるバグ修正TDDの計4テンプレートを示します。

  1. Red:失敗するテストだけを先に書かせる(実装はしない)
  2. Green:そのテストを通す最小の実装を書かせる
  3. Refactor:テストを通したまま挙動を変えずに整理させる
  4. バグ修正TDD:再現する失敗テストを書いてから修正に入らせる

依頼文の骨格はClaude Codeに伝わるプロンプトの基本構造、計画フェーズの強制はClaude Codeに「計画してから実装」させるプロンプト例、リファクタ特有の制約はClaude Codeで既存コードを壊さずリファクタリングする依頼文に詳しいので、本記事はTDD固有のループ構造にフォーカスします。

なぜAIコーディングでTDDが効くのか

「AIが速く実装できるなら、テストは後回しでいい」と感じるかもしれません。しかし実際は逆で、Claudeに任せる範囲が広いほど、テストが先にあるほうが安全です。理由は3つあります。

  • 検証ループが短くなる:失敗テストがあれば、Claudeは「通すべきもの」を機械的に確認できる。人間が画面を見続ける必要が減る
  • 過剰実装を防げる:先にテストで仕様を固めると、Claudeが頼んでもいない機能を勝手に追加しにくくなる
  • 修正の根拠が残る:「なぜこの分岐を直したか」が、テストケース名から自動的に説明される

逆にテストなしで頼むと、Claudeは**「動いているように見える」コード**を返してしまい、人間が境界条件を一つ一つ確認する羽目になります。

Red:失敗するテストだけを先に書かせる

最初のフェーズで一番大切なのは、**「実装に手を出させない」**ことです。Claudeはテストを書いた直後に「ついでに実装も用意しました」とやりがちなので、依頼文で明示的に止めます。

Redフェーズの依頼テンプレ

## 目的
{{機能名}} の仕様を、失敗するテストとして先に書く。
今フェーズで実装は一切書かない。

## 入力
- 仕様: {{1〜3行の仕様要約}}
- 既存テストファイル: @tests/{{path}}.test.ts
- 既存実装ファイル: @src/{{path}}.ts (現在は未実装または空関数)

## 出力
- @tests/{{path}}.test.ts に以下のケースを追加する
  1. 正常系: {{入力}} → {{期待出力}}
  2. 境界値: {{入力}} → {{期待出力}}
  3. 異常系: {{入力}} → {{期待エラー}}

## 完了条件
- `npm test -- {{path}}` を実行し、追加した3ケース全てが Red(失敗)であることを確認する
- 失敗メッセージを報告する("expected X but received Y" の形)

## 禁止事項
- @src/{{path}}.ts に手を加えない
- 既存テストを書き換えない
- スキップ(it.skip / test.skip)を使わない

ポイントは**「Redで止まる」ことを完了条件にしている**点です。テストが緑だったらそれは仕様が間違っているか、既に実装が存在しているかなので、その時点で人間が判断します。

Plan Modeで仕様の解像度を上げてから書く

仕様が曖昧なまま依頼すると、Claudeは想像で穴を埋めます。テストを書く前にPlan Modeで仕様を確定させると安定します。

claude --permission-mode plan
@docs/spec.md と @src/{{path}}.ts を読んで、
{{機能名}} の仕様を「入力・期待出力・例外」の表にまとめて。
曖昧な点があれば AskUserQuestion で先に聞いて。

公式のCommon Workflowsも、Plan ModeでAskUserQuestionを使って仕様を詰めてから実装に入る流れを推奨しています。

Green:そのテストを通す「最小」の実装を書かせる

Redが揃ったら、**「このテストだけを通せばよい」**という制約で実装を書かせます。最小実装でないと、後のRefactorフェーズで何を整理してよいかが分かりません。

Greenフェーズの依頼テンプレ

## 目的
@tests/{{path}}.test.ts の以下3ケースを通す最小実装を @src/{{path}}.ts に書く。
- 正常系: {{name}}
- 境界値: {{name}}
- 異常系: {{name}}

## 制約
- そのテストを通すために必要な変更だけにする
- 仕様外の機能(ログ出力、エラー文整形、コメント整備)は今回入れない
- 新しい依存パッケージを追加しない
- 公開シグネチャを既存呼び出し元と矛盾させない

## 出力
- 変更したファイルのリスト
- 各ファイルでの変更要約(1ファイル1〜2行)
- 触っていないが影響を受けそうな箇所

## 完了条件
1. `npm test -- {{path}}` で対象3ケースが Green
2. `npm test` 全体が Green(既存テストを壊していない)
3. `git diff --stat` を実行し、変更ファイルが想定の範囲に収まっている

## 禁止事項
- テストを書き換えて通すこと(テスト改変は本末転倒)
- console.log を残すこと
- 動かしながら try/catch で例外を握りつぶすこと

仕様外の機能を今回入れない」を明示しないと、Claudeは親切心でログ整形やドキュメンテーションコメントを足してきます。これがレビュー時の差分を膨らませる主因なので、明示的に止めてください。

テスト改変での「Green」を見抜く

Claudeがどうしても通せないとき、まれにテスト側を緩めて通すことがあります。例えばexpect(x).toBe(5)expect(x).toBeTruthy()に書き換えるパターンです。これを防ぐには、git diff tests/を必ず人間が読むことです。差分にテストファイルの変更が含まれていたら、Greenの依頼文を破っているサインなので、/rewindまたはチェックポイント復元で巻き戻します。

Claude Codeの成功率を上げる制約条件と受け入れ条件の作り方で書いたように、「テスト改変禁止」は完了条件ではなく禁止事項に書くのがコツです。完了条件に書くと「禁止が達成される」状態を目指してしまい、認識がぶれます。

Refactor:テストを保ったまま挙動を変えずに整理する

Greenでテストが通ったら、最小実装にありがちな重複・命名のズレ・関数長を整えます。Refactorはリファクタリングと完全に同じ意味なので、すでにClaude Codeで既存コードを壊さずリファクタリングする依頼文で書いた**「API不変」「特性化テスト先行」**の原則がそのまま使えます。

Refactorフェーズの依頼テンプレ

## 目的
@src/{{path}}.ts をリファクタする。挙動は1つも変えない。

## 制約(最重要)
- 公開シグネチャ(関数名・引数・戻り値の型)は不変
- @tests/{{path}}.test.ts は1文字も変更しない
- 新しい依存を追加しない
- 1コミット = 1意図の単位で整理する

## 整理してよい範囲
- 内部関数の抽出
- 命名(内部のみ)の改善
- 重複の統合
- ガード節への書き換え

## 完了条件
1. `npm test` 全体が Green
2. `git diff tests/` の差分が空(テストに触っていない)
3. 公開シグネチャ差分が空(`git diff src/{{path}}.ts` で型と関数名が変わっていない)

最後の2条件がRefactorフェーズがGreenフェーズと混ざらないための歯止めです。テストファイルの差分が出た瞬間にやり直してください。

コミットを分けるとレビューが楽になる

Red・Green・Refactorはそれぞれ別コミットにすると、PRレビュー時にRed→Greenで「仕様」が、Green→Refactorで「整理」だけが読めます。Conventional Commitsを使っているなら次のような分け方が分かりやすいです。

test(parser): add empty-line cases to CSV parser    # Red
feat(parser): handle empty lines in CSV parser      # Green
refactor(parser): extract trim helper               # Refactor

コミット粒度の運用はClaude Codeで安全にコミットとPRを作るワークフローを参照してください。

バグ修正TDD:再現する失敗テストを書いてから直す

新規実装ではないバグ修正でも、**「失敗テストを書いてから修正する」**フローはそのまま使えます。Best Practicesも「症状を伝え、失敗テストで再現させてから直させる」流れを推奨しています。

バグ修正TDDの依頼テンプレ

## 症状
{{再現条件}} のとき、{{期待挙動}} のはずが {{実際の挙動}} になる。
スタックトレース:
{{stack trace}}

## やること(順序厳守)
1. まず @tests/{{path}}.test.ts に、このバグを再現する失敗テストを1ケース追加する
2. `npm test -- {{path}}` で Red であることを報告する(ここで一度止まる)
3. 私が確認の合図を出してから、@src/{{path}}.ts を修正する
4. 同じテストが Green になることを確認する
5. `npm test` 全体が Green であることを確認する

## 制約
- 1で「ついでに直す」をしない(必ず Red を見せる)
- 修正は最小範囲。symptoms ではなく root cause を直す
- 既存テストの期待値を変えない

「ここで一度止まる」を依頼文に書いておくと、Claudeは1の時点でAskUserQuestion相当の確認を求めてくれます。Redが本当にバグを再現しているかを人間が確認する間が生まれるので、誤った前提のまま修正に入る事故が防げます。

Plan Modeとの組み合わせ表

フェーズPlan Modeの使いどころNormal Modeの使いどころ
Red仕様が曖昧/既存テストパターンの調査テスト追記そのもの
Green影響範囲の調査が必要なとき実装の追記
Refactor抽出候補の探索実際の整理
バグ修正TDD原因仮説の探索テスト追加と修正

仕様や原因の解像度が低いフェーズだけPlan Modeを使い、書き始めたらNormal Modeに戻す、が基本です。Plan Modeを使いっぱなしだと、書き出すべきタイミングを逃します。

やってはいけないアンチパターン

  • テスト全部を一気に書かせる:1セッションで20ケース書かせると、Claudeが仕様を取り違えても気付けない。3〜5ケース単位でRed→Greenを回す
  • Greenの判定を口頭で済ませる:「テスト通った?」「通りました」で終わらせない。npm testの生ログを依頼文の完了報告に入れさせる
  • Refactorで挙動を変える:「ついでにこの分岐も整理」が一番危険。挙動変更は別コミット・別タスクに分ける
  • テストを変えてGreenにする:禁止事項に明記し、git diff tests/を必ず読む
  • Mock地獄:実DBや実ファイルを触ったほうが速い場面までMock化しない。Mockが多いほどテストの信頼性は下がる

依頼前の30秒チェックリスト

  • 今回の3〜5ケースの入力・期待出力・例外を表にできている
  • テストランナーの実行コマンドを依頼文に書いた(npm test -- path など)
  • フェーズ(Red / Green / Refactor / バグ修正)を依頼文の冒頭に書いた
  • 禁止事項を明示した(テスト改変禁止、依存追加禁止など)
  • 完了条件に生ログの報告を含めた

ここまで揃えれば、Claude Codeは**「テストの赤と緑を1セッションで回せる、根拠あるTDDパートナー」**として機能してくれます。最小実装で止め、人間が差分を読み、リファクタは別コミットに分ける。この3点を守れば、AI生成コードでもテストカバレッジと可読性は両立できます。

次に読む