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文字)
- 特殊文字を含む文字列(例: "<script>", "'; DROP TABLE")
パターン5:テスト名が意味を持たない
症状: it('should work'), it('test case 1') のような名前が並ぶ。
原因: テスト名のフォーマット指定がない。
プロンプト修正:
テスト名は以下のフォーマットで書いてください:
it('[入力条件] の場合、[期待される結果]', ...)
例:
- it('メールアドレスが空文字の場合、ValidationError をスローする', ...)
- it('パスワードが8文字未満の場合、"パスワードは8文字以上" エラーメッセージを返す', ...)
- it('正常な入力の場合、id プロパティを持つ User オブジェクトを返す', ...)
テスト名を読むだけで「何をテストしているか」がわかるように書いてください。
実践ワークフロー:hooks連携
Claude Code Hooks 実践で紹介した PreToolUse フックを使うと、テスト生成ルールをプロンプトに自動注入できます。
.claude/settings.json に以下を追加します。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "bash -c 'if echo \"$CLAUDE_TOOL_INPUT\" | grep -q \"\\.test\\.ts\"; then cat .claude/test-generation-rules.md; fi'"
}
]
}
]
}
}
.claude/test-generation-rules.md にプロジェクト固有のテスト生成ルールをまとめておくと、毎回コンテキストを貼らなくても自動的に参照されます。
## テスト生成ルール(自動注入)
- フレームワーク: Vitest 1.x
- スタイル: describe/it、vi.mock()
- テスト名フォーマット: 「[条件] の場合、[結果]」
- モック対象: DB(prisma)、外部API(axios)のみ
- エラー系テストを正常系と同数以上含める
このワークフローにより、チーム全員が同じテスト生成品質を保てます(経験則)。
AI生成コードのテスト戦略と組み合わせることで、生成したテストをどのCI/CDパイプラインに組み込むかの全体設計も見えてきます。
FAQ
Q. Claude Code に書かせたテストはそのままコミットしても大丈夫?
A. ステップ4の人間レビューを経た後なら問題ありません。特に「仕様の正確性」は人間が確認する必要があります。生成テストの pnpm test 実行確認と、期待値が本当に意図した仕様を表しているかのチェックは省略しないでください。
Q. 既存テストがないプロジェクトでもコンテキスト注入はできる?
A. できます。「既存テストの参照」は省略可能です。その場合、ステップ1のコンテキストに「テストスタイルはゼロから定義する。Vitest + describe/it + vi.mock() を標準とする」と明記してください。既存テストがある場合より初回生成品質は落ちますが(経験則)、2〜3ループで安定します。
Q. テスト生成に毎回このステップを踏むのは非効率では?
A. 初回は確かに手間がかかります。しかし .claude/test-generation-rules.md を一度整備すれば、「hooks連携」セクションで説明したように自動注入できます。1プロジェクトで1回の整備コストです。また、ステップ2〜4は慣れれば1〜2分で終わります(経験則)。
Q. TDD(テストファースト)にも使えるか?
A. 使えます。その場合はステップ1の「テスト対象コード」を省略し、代わりに「実装予定の仕様書」や「関数のインターフェース定義」を渡します。Claude Code は仕様ベースでテストを生成し、あなたはそのテストをグリーンにする実装を書きます。LLM出力の品質ゲート設計と組み合わせると、AIが生成した実装コードの品質チェックにも応用できます。
Q. TypeScript 以外でも同じアプローチが使える?
A. 基本的な考え方(コンテキスト注入・セルフチェック・失敗パターン対処)はどの言語でも使えます。ステップ1のコンテキスト内容をPython(pytest)やGo(testing package)向けに書き直すだけです。フレームワーク固有の部分(モックのスタイル、アサーション構文)は言語に合わせて調整してください。
👉 シリーズ全体像: Claude Code 環境セットアップガイド
まとめ
Claude Code にテストを書かせるときの品質は、プロンプト設計で8割が決まります(経験則)。
本記事で紹介した4ステップループのポイントは以下の通りです。
- コンテキスト注入: フレームワーク・守りたい仕様・既存テストパターンを渡す
- 生成プロンプト: リストアップ→コードの2段階指示で乖離を事前に修正
- セルフチェック指示: 実行不能・網羅性の問題を自動修正させる
- 人間レビュー: 仕様の正確性・モックの妥当性・実行確認を人間が担う
失敗パターン5種(ハッピーパス偏重・モック過剰・実行不能・境界値抜け・テスト名不明確)のプロンプト修正テンプレートをそのままコピーして使えます。
さらに自動化を進めるなら、LLM出力の品質ゲート設計でテスト実行をCI/CDに組み込む設計も参照してください。
References
- Claude Code 公式ドキュメント — Claude Code の基本機能・設定方法
- Claude Code Hooks 公式ドキュメント — フックの種別・設定方法
- Vitest 公式ドキュメント — モック・カバレッジ設定の詳細
- Jest 公式ドキュメント:Mock Functions — vi.mock() の元となるモックパターン
- Google Testing Blog: Test Sizes — ユニット/統合/システムテストの定義(公式値参照元)
- Martin Fowler: TestDouble — モックとスタブの使い分けの一次ソース
