TL;DR
📚 シリーズ: Claude Code シリーズ:環境設定から実践まで
- 「コード渡して書いて」だけでは失敗する。コンテキスト注入が品質を決める(経験則)
- 4ステップループ(コンテキスト注入→生成→セルフチェック→人間レビュー)で再現性を確保
- 失敗パターン5種とプロンプト修正テンプレートを使えばすぐ改善できる
はじめに
こんにちは、みねです。
Claude Code でテストを書かせてみたら、こんな経験はないでしょうか。
生成されたテストはパスする。でも、本当に重要なエッジケースが1つも入っていない。
モックを大量に書いてくれたが、実際には実行できないコードだった。
ハッピーパスばかりで、バリデーションエラーや境界値が一切テストされていない。
Claude Code は「コードの構文」は知っている。しかし、あなたのコードが何を守りたいかは知らない。この認識のギャップが「惜しいテスト」を生む根本原因です。
本記事では、テスト生成の失敗の本質を解説し、4ステップのテスト生成ループと失敗パターン別プロンプト修正テンプレートを提供します。
失敗の根本原因:コンテキスト不足
Claude Code にテスト生成を依頼するとき、多くの場合このようなプロンプトになります。
このコードのテストを書いて。
[ソースコードを貼り付け]
これは失敗の定石です。Claude Code が受け取っている情報はソースコードだけ。以下の情報がまったく渡されていません。
- テストフレームワーク・スタイル: Vitest か Jest か、describe/it 派か test 関数派か
- 既存テストのパターン: モックのスタイル、アサーションの粒度
- 守りたい仕様: このコードが「何をしてはいけないか」「どんな入力で壊れてはいけないか」
- テストの目的: ユニットテストか統合テストか、カバレッジ基準は何か
Claude Code は「それっぽいテスト」を生成します。しかし「あなたのプロジェクトに合ったテスト」を生成するためには、その文脈を渡す必要があります。
AIとペアプロする実践パターンでも触れたように、AI への指示品質はコンテキスト設計で8割が決まります。テスト生成も例外ではありません。
4ステップ・テスト生成ループ
失敗を避けるために、以下の4ステップを毎回実行します。1回で完璧なテストを求めるのではなく、ループ前提の設計が重要です。
ステップ1:コンテキスト注入
テスト生成の前に、必ず次の4要素を渡します。
## テスト生成コンテキスト
### テストフレームワーク
- フレームワーク: Vitest 1.x
- スタイル: describe/it ブロック、vi.mock() を使用
- 既存テストの参照: tests/utils/validateUser.test.ts
### 守りたい仕様(テストすべき振る舞い)
- メールアドレスが空文字の場合は ValidationError をスローする
- パスワードが8文字未満の場合は ValidationError をスローする
- 正常入力の場合は User オブジェクトを返す
- DB接続エラーの場合は DatabaseError をスローする(DBはモック必須)
### テスト対象コード
[ソースコードをここに貼る]
### テストの目的
ユニットテスト。DB・外部サービスはすべてモック。
カバレッジ目標: 分岐網羅(branch coverage)80%以上。
「守りたい仕様」の列挙が最も重要です。ここを省くと、Claude Code は実装から仕様を逆算しようとしますが、精度は落ちます(経験則)。
ステップ2:生成プロンプト
コンテキストを渡した後、生成を指示します。
上記のコンテキストを踏まえて、以下の手順でテストを作成してください。
1. 上記「守りたい仕様」の各項目に対応するテストケースを1件ずつ作成する
2. 仕様に明記されていないが、実装を読んで追加すべきエッジケースを3件以内で提案し、テストを書く
3. 既存テストファイル(tests/utils/validateUser.test.ts)のスタイルに合わせる
4. モックは vi.mock() を使い、テストファイルの先頭にまとめる
5. 各 it ブロックに1行の日本語コメントで「何を確認するか」を書く
まず、作成するテストケース一覧をリストアップしてから、コードを書いてください。
ポイント: 「まずリストアップ、次にコード」という2段階指示により、Claude Code が何をテストするかを明示させます。リストと実装に乖離があれば、コード生成前に修正できます。
ステップ3:セルフチェック指示
生成後、Claude Code 自身にセルフチェックを依頼します。
生成したテストについて、以下の観点でセルフチェックしてください。
チェックリスト:
- [ ] すべてのテストが実際に実行可能か(import パスが正しいか)
- [ ] 「守りたい仕様」の全項目がカバーされているか
- [ ] ハッピーパスだけでなく、エラー・境界値・例外ケースがあるか
- [ ] モックが適切か(実装の詳細ではなく、振る舞いをモックしているか)
- [ ] `any` 型や `@ts-ignore` を使っていないか
問題があれば修正し、問題がなければ「セルフチェック完了」と報告してください。
このセルフチェックにより、実行不能コードや明らかな抜けを自動的に修正させます。人間レビューの前段として機能します。
ステップ4:人間レビューのポイント
セルフチェック後でも、人間が確認すべき点があります。
必ず人間がチェックする項目:
- 仕様の正確性: テストに書かれた期待値が、本当にあなたが守りたい仕様か
- モックの妥当性: モックが実際の実装を正しく模倣しているか
- テスト名の意味:
it('should work', ...)のような名前になっていないか - 実行確認:
pnpm testを実際に実行し、すべてグリーンか
自動化できる部分を Claude Code に任せ、判断が必要な部分を人間が担う。この分業が効率的なループを作ります。
失敗パターン5種と対処法
実際の運用で頻出する失敗パターンと、プロンプト修正テンプレートを示します。
パターン1:ハッピーパス偏重
症状: 正常系のテストは多いが、エラー・例外系がほぼない。
原因: 仕様に正常系しか書いていない。
プロンプト修正:
テストケースを作成する際、以下の割合を意識してください:
- 正常系: 30%
- エラー系(バリデーションエラー、権限エラー等): 40%
- 境界値・エッジケース: 30%
特に以下のエッジケースを必ずカバーしてください:
- 空文字・null・undefined の入力
- 最大値・最小値の境界
- [固有のエッジケースがあれば記載]
パターン2:モック過剰
症状: 実装の内部詳細までモックしており、実装が変わるたびにテストが壊れる。
原因: 「何をモックすべきか」の指定がない。
プロンプト修正:
モックの原則を守ってください:
- モックするのは「外部依存」(DB、API、ファイルシステム)のみ
- 内部のプライベートメソッドやモジュール内関数はモックしない
- vi.spyOn() より vi.mock() を優先する
- モック対象: [DB クライアント], [外部 API クライアント]
- モック不要: [ユーティリティ関数], [バリデーションロジック]
パターン3:実行不能コード
症状: 生成されたテストが import エラーやパスエラーで実行できない。
原因: プロジェクトのディレクトリ構造・パス規則を渡していない。
プロンプト修正:
## ファイルパス規則
- テストファイルの配置: tests/[同じディレクトリ構造]/[ファイル名].test.ts
- テスト対象のimportパス: 相対パスを使用(例: ../../src/utils/validate)
- モジュールの alias: @/ = src/ (tsconfig.json の paths 設定)
- テストセットアップファイル: tests/setup.ts(自動実行済み、再importは不要)
パターン4:境界値の抜け
症状: ステップ1で仕様を渡したが、数値・文字列の境界値テストがない。
原因: 境界値テストの重要性が伝わっていない。
プロンプト修正:
数値・文字列パラメーターに対しては、必ず以下の境界値テストを追加してください:
数値の場合:
- 最小値(例: 0)
- 最小値-1(例: -1)
- 最大値(例: 100)
- 最大値+1(例: 101)
- 典型的な中間値(例: 50)
文字列の場合:
- 空文字 ""
- 最小長(例: 1文字)
- 最大長(例: 255文字)
- 最大長+1(例: 256文字)
- 特殊文字を含む文字列(例: "
