Claude Codeに機能をまるっと実装させると、こういう経験ありませんか。
- 最初は良さそうに見えたのに、よく見ると要件の半分しか満たしていない
- 「ついでに」関係ないファイルまで書き換えてくる
- 修正を頼むと、直したはずの別の箇所が壊れる
- 「動きました!」と言うが、実際に走らせるとエラーで落ちる
- 5往復もすると、もう何が正しい挙動なのか自分でも分からなくなる
これ、モデルが馬鹿だからではありません。**「正解(仕様)が言葉でしか定義されていない」**のが原因です。
自然言語の仕様は曖昧で、解釈の幅があります。Claude Codeはその幅の中で「それっぽいもの」を生成し、あなたは出力を見て「いや、そうじゃなくて」と言葉で追記する。この往復が続くと、仕様はどんどんブレていきます。
これを止める一番シンプルな方法が TDD(テスト駆動開発) です。テストを先に書かせると、それが機械が検証できる仕様の固定になります。Claude Codeはもう「それっぽいもの」では合格できず、テストが緑になるまで実装し続けるしかなくなる。
この記事では、Claude CodeでTDDのループ(テスト→実装→リファクタ)を実際に回す手順を、コピペできるプロンプト付きで紹介します。すべて今日のセッションから試せます。
なぜテストが「暴走を防ぐ柵」になるのか
まず原理だけ押さえます。ここが腑に落ちると、あとの手順は自然に守れます。
自然言語の指示とテストコードの決定的な違いは、**「合否を誰が判定するか」**です。
| 仕様の形 | 合否の判定者 | 起きること |
|---|---|---|
| 自然言語の指示だけ | あなた(人間が目視) | 解釈がブレる・見落とす・往復が増える |
| 先に書いたテスト | テストランナー(機械) | 緑/赤で明確・Claudeが自分で確認できる |
テストを先に書くと、次の3つが同時に手に入ります。
- 仕様が固定される — 「正しい挙動」がコードとして1つに定まる。あとから「やっぱりこうして」と言葉で揺らしても、テストを変えない限り基準はブレない
-
Claudeが自己検証できる — 実装したら自分で
npm testを走らせ、赤なら直す。あなたが目視でレビューする前に、Claude自身が最低ラインを担保する - 修正が安全になる — リファクタや追加機能で既存挙動を壊すと、テストが赤くなって即バレる。「直したら別が壊れた」の無限ループから抜けられる
つまりテストは、Claude Codeにとっての**「越えてはいけない柵」**です。柵がないと自由に走り回って迷子になりますが、柵があれば走る範囲が決まる。これがTDDが暴走を防ぐ仕組みです。
補足: ここで言うTDDは「テストファースト」の意味で使っています。厳密なt-wada流の三角測量まで再現する必要はありません。「実装より先に、合格条件をコードで固定する」——この1点さえ守れば効果は出ます。
基本ループ: Red → Green → Refactor をClaudeで回す
TDDの基本サイクルは3ステップです。これをそのままClaude Codeに割り当てます。
1. Red : 失敗するテストを書く(まだ実装がないので赤)
2. Green : テストが通る最小限の実装を書く(赤→緑)
3. Refactor: 緑を保ったままコードを整える
重要なのは、この3ステップを1つの指示で一気にやらせないことです。一気にやらせると「テストも実装も同時に生成」してしまい、テストが実装に都合よく書かれてしまいます。それでは仕様の固定になりません。
ステップを分けて、各ステップで一度止めるのがコツです。
ステップ1: 失敗するテストだけを書かせる(Red)
最初の指示では実装を禁止します。テストだけを書かせ、実際に赤くなることを確認させます。
これから消費税計算関数 calcTax を作ります。まずTDDのRedフェーズだけやってください。
【今やること】テストだけを書く。実装は一切書かない。
【仕様】
- calcTax(price, rate) を作る
- price: 税抜価格(整数), rate: 税率(0.1 等の小数)
- 戻り値: 税込価格。1円未満は切り捨て
- price が負数なら Error を投げる
【出力】
- tests/calcTax.test.ts にテストを書く
- 正常系・境界値・異常系を網羅
- テストを実行し、実装がないため失敗することを確認して報告
ここでのポイントは2つ。
- 「実装は書くな」と明示する — これを言わないとClaudeは親切心で実装まで書いてしまい、テストが「実装ありき」になります
- 「失敗を確認しろ」と言う — テストが赤くなることまで確認させると、「テストが本当に動く状態」であることが保証されます。緑になるはずのないテストがなぜか緑なら、それはテスト自体が壊れています
この時点で生成されたテストを必ず人間が読みます。ここがTDD最大の関門です(後述)。テストが仕様として正しいかを、ここで確定させます。
ステップ2: テストを通す最小実装を書かせる(Green)
テストが確定したら、次は実装。指示は驚くほどシンプルになります。
さっき確定した tests/calcTax.test.ts を通す実装を書いてください。
【制約】
- テストを通すための最小限の実装にとどめる
- テストファイルは変更しない(仕様は固定)
- 実装後、必ず npm test を実行して全件緑になるまで直す
ここで効いてくるのが 「テストファイルは変更するな」 の一文です。これがないと、Claudeは実装がテストを通らないときに「テストのほうを実装に合わせて書き換える」という最悪の手を打ちます。仕様が実装に侵食される瞬間です。テストを凍結することで、Claudeは「実装を直す」以外の逃げ道がなくなります。
そして 「全件緑になるまで直す」。これでClaudeは自分でテストを走らせ、赤があれば自分で修正するループに入ります。あなたが目視する前に、機械的な合格ラインはClaude自身が担保してくれます。
ステップ3: 緑を保ったままリファクタさせる(Refactor)
テストが緑になったら、コードを整えます。ここでもテストが守ってくれます。
calcTax.ts をリファクタしてください。
【制約】
- 振る舞いは一切変えない
- tests/calcTax.test.ts は変更しない
- リファクタの各ステップ後に npm test を走らせ、常に緑を維持
【観点】
- マジックナンバーを定数化
- 早期returnで分岐を浅く
リファクタは「振る舞いを変えずに構造を改善する」作業です。テストが緑のままなら振る舞いは保たれている、という保証があるからこそ安心して構造をいじれます。テストなしのリファクタはただの書き換えで、デグレが怖くて踏み込めません。
Before / After: 同じ機能を2通りで作らせる
「ログイン失敗を5回でアカウントロックする」機能を例に、TDDなしとありを比べます。
Before: いきなり実装させる
ログイン失敗が5回続いたらアカウントをロックする機能を作って
返ってくる実装は、一見それらしく動きます。が、こういう穴が後から発覚しがちです。
- 「5回目でロック」なのか「5回失敗した次(6回目)でロック」なのか曖昧
- ログイン成功で失敗カウントがリセットされるか不明
- ロック後の挙動(解除条件・エラーメッセージ)が未定義
- これらを指摘するたびに言葉で往復 → 直すと別の条件が壊れる
仕様が言葉のままなので、境界がすべて曖昧です。Claudeは曖昧な部分を勝手に埋め、あなたは出力を見て初めて「そこ違う」と気づく。後追いの修正合戦になります。
After: 先にテストで境界を固定する
ログイン失敗ロック機能を作ります。まずRedフェーズ。テストだけ書いてください。
実装は書かない。
【仕様 = テストで固定したい境界】
- 失敗4回まではロックされない
- 失敗5回ちょうどでロックされる
- ロック中はカウント増加に関わらず弾く
- 失敗が5回未満のときログイン成功でカウントは0にリセット
- ロック中に正しいパスワードでもログインは拒否される
【出力】tests/accountLock.test.ts に上記を1ケースずつテスト化し、失敗を確認
テストを書かせた時点で、曖昧だった境界がすべてコード上の数値・分岐として確定します。「5回ちょうど」「4回まではOK」「成功でリセット」が、それぞれ独立したテストケースになる。この状態で実装を頼めば、Claudeはこの境界を1つも外せません。外したらテストが赤くなるからです。
| 観点 | Before(言葉だけ) | After(テスト先行) |
|---|---|---|
| 境界条件 | 実装後に発覚 | 着手前に確定 |
| 仕様のブレ | 往復のたびに揺れる | テストで凍結され不変 |
| デグレ検知 | 動かして初めて気づく | テストが即赤くなる |
| レビュー対象 | 実装コード全部 | まずテストだけ読めばよい |
| 修正の収束 | 往復で発散しがち | 緑になれば終わり |
Afterの最大の利点は、レビューの対象が「実装全部」から「テストだけ」に変わることです。テストさえ正しければ、実装が緑になった時点で仕様は満たされています。読む量が激減します。
CLAUDE.mdに「TDDを標準にする」一文を入れておく
毎回プロンプトで「テストから書いて」と指示するのは面倒です。プロジェクトの CLAUDE.md に方針を書いておけば、Claudeが標準でTDDの順序を守るようになります。
## 実装の進め方
機能追加・バグ修正は原則テストファーストで進める。
1. まず失敗するテストを書き、テストが赤いことを確認してから止まる
2. テストの妥当性を私(人間)が確認するまで実装に進まない
3. 実装はテストを通す最小限にとどめ、テストファイルは勝手に変更しない
4. 実装後は必ずテストを実行し、全件緑を確認してから報告する
5. リファクタ時も常にテストを緑に保つ
ポイントは 「テストが赤い時点で一度止まる」 を明文化すること。これでステップ1とステップ2の間に人間のレビューが必ず挟まり、仕様の妥当性チェックが飛ばされなくなります。
CLAUDE.mdの細かい設計やHooksでの自動化は本記事の範囲外ですが、「TDDを標準動作にする一文」だけでも入れておくと、毎回の指示が一気に楽になります。
よくある失敗5つと回避策
TDDをClaude Codeで回すとき、特定の失敗パターンに必ずぶつかります。先に知っておけば避けられます。
失敗1: テストと実装を同時に書かせてしまう
一番多い失敗です。「テスト書いて実装して」と一息で頼むと、Claudeはテストを実装に都合よく書きます。実装が間違っていても、その間違いに合わせたテストが書かれるので両方緑になり、バグが温存されます。
回避策: Redフェーズ(テストのみ)とGreenフェーズ(実装)を必ず分け、間に人間のレビューを挟む。「実装は書くな」を毎回明示する。
失敗2: 生成されたテストを読まずに進む
TDDの効果は**「テストが正しい仕様である」**ことが前提です。テストが間違っていれば、Claudeは間違った仕様を完璧に実装します。これはTDDなしより危険——間違いが「緑」のお墨付きを得るからです。
回避策: Redフェーズで生成されたテストは必ず人間が読む。特に「期待値(expect)が本当に正しいか」を1ケースずつ確認する。ここだけは絶対に省略しない。テストを読む時間が、実装全体を読む時間より遥かに短いことを思い出してください。
失敗3: 実装が通らないとテストのほうを書き換える
実装がどうしても通らないとき、Claudeは「テストを実装に合わせて修正しました」とやることがあります。仕様が実装に負けた瞬間です。
回避策: 「テストファイルは変更しない」を制約に必ず入れる。テストを変える必要が本当にあるなら、それは仕様変更なので人間が判断する、と明確に分ける。
失敗4: 「動きました」を信じて実行を確認しない
Claudeは実装後に「テストが全て通りました」と報告することがありますが、実際にはコマンドを走らせていないことがあります。生成しただけで「通るはず」と推測で報告するケースです。
回避策: 「必ず npm test を実行し、その出力(緑の件数)を貼って報告して」と指示する。実行ログを見せさせれば、推測報告を弾けます。
失敗5: テストの粒度が荒すぎる / 細かすぎる
1つのテストで何もかも検証しようとすると、落ちたときに原因が分からない。逆に細かすぎると、些細な実装変更でテストが大量に壊れて保守が地獄になります。
回避策: 「1ケース1観点(境界値・正常系・異常系を別ケースに分ける)」を指示する。失敗1ケース=仕様1項目、の対応が取れていると、赤を見た瞬間にどの仕様が壊れたか分かります。
| 失敗 | 一言での回避策 |
|---|---|
| 1. テストと実装を同時生成 | Red/Greenを分け、間にレビュー |
| 2. テストを読まず進む | Redで生成テストを必ず人間が読む |
| 3. テストを書き換えて逃げる | 「テストは変更しない」を制約に固定 |
| 4. 実行せず「通った」と報告 | テスト実行ログの提出を必須化 |
| 5. テストの粒度が不適切 | 1ケース1観点を徹底 |
バグ修正にこそTDDが効く
新機能だけでなく、バグ修正でTDDは特に強力です。手順はこうです。
1. まず「そのバグを再現する失敗テスト」を書かせる(実装は触らない)
→ バグが本当にテストで赤くなることを確認
2. そのテストが緑になるよう実装を直させる
3. 全テストを走らせ、他が壊れていないことを確認
具体例:
「カートの合計が、数量0の商品を含むと NaN になる」というバグがあります。
まず実装は直さず、このバグを再現する失敗テストだけを書いてください。
数量0の商品を含むカートで合計を計算し、NaN にならず正しい数値になることを
期待するテストです。実行して、現状では赤くなることを確認して報告してください。
この手順の何が良いか。
- バグが本当に「テストで捕まる形」になる — 再現テストが赤くなって初めて、バグの正体が確定する
- 同じバグが二度と起きない — 修正後もこのテストが残るので、将来のリグレッションを防ぐ防波堤になる
- 「直ったつもり」を排除できる — テストが緑になって初めて「直った」と言える。目視で「たぶん直った」がなくなる
バグ報告を受けたら、修正を頼む前に「まず再現テストを」。これを習慣にすると、修正の確実性が一段上がります。
まとめ: テストはClaude Codeへの「機械が読める仕様書」
TDDをClaude Codeで回す要点をまとめます。
| ステップ | やること | 守るべき制約 |
|---|---|---|
| Red | 失敗するテストだけ書かせる | 実装を書かせない・失敗を確認させる |
| (レビュー) | 生成テストを人間が読む | 期待値が正しいか1ケースずつ確認 |
| Green | テストを通す最小実装 | テストファイルは変更させない・実行ログ提出 |
| Refactor | 緑を保ったまま整える | 振る舞いを変えない・常に緑 |
Claude Codeが暴走するのは、賢くないからではなく、正解が言葉でしか定義されていないからです。テストを先に書かせれば、それが機械の読める仕様の固定になり、Claudeは「それっぽいもの」では合格できなくなります。柵の中でしか走れなくなる。
最初の一歩は簡単です。次にClaude Codeに何かを実装させるとき、いきなり「作って」と言う代わりに、**「まず失敗するテストだけ書いて。実装は書かないで」**と打ってみてください。生成されたテストを読んだ瞬間、自分の頭の中の仕様がいかに曖昧だったか気づくはずです。そこを固定するだけで、その後の往復が劇的に減ります。
補足: 試すための無料リポジトリ
本記事の内容を実際のプロジェクトで試すには、土台となるCLAUDE.mdとフォルダ構成があるとスムーズです。私が使っているスターター構成を無料で公開しています。
無料スターター(GitHub):
https://github.com/noguso245-jpg/claude-code-skills-starter
さらに踏み込んで、ワークフローやサブエージェント設計を「実行可能なスキルファイル」としてまとめたパッケージも用意しています。手元で /コマンド として呼び出せる形です。
-
スターターパック(¥1,980): CLAUDE.mdテンプレ7種・Hooks・MCP設定
https://streamsolty.gumroad.com/l/gliwz -
ワークフローOS(¥9,800): 79本のスキル + ワークフロー3本 + プロンプト10種
https://streamsolty.gumroad.com/l/vhcysn
まずは無料リポジトリから試して、もっと体系的に使いたくなったら検討してもらえれば十分です。記事の内容だけでも効果は出ます。
最新のTipsはXでも発信しています: @k___n___t_1125