はじめに
テストを書くのは大事だとわかっていても、既存のコードにテストを追加する作業は後回しにしがちです。Claude Codeを使えば、既存コードのテスト生成を大幅に効率化できます。
ただし、「テストを書いて」とだけ指示すると、期待通りの品質にならないことがあります。このレシピでは、テスト生成のプロンプトパターンと、生成されたテストの品質を上げるためのコツを紹介します。
手順
テスト対象のコードを特定する
まずは、テストが不足しているコードを見つけましょう。Claude Codeに聞くのが手っ取り早い方法です。
src/services/ にあるファイルで、テストがカバーされていない関数を一覧にして特定のファイルに対して聞くこともできます。
@src/services/userService.ts のテストカバレッジを確認して。テストがない関数を教えてテストフレームワークを指定して生成する
テストを生成するときは、フレームワークと基本方針を明確に伝えましょう。プロジェクトに既存のテストファイルがあれば、そのパターンに合わせてくれます。
Jest / Vitestの場合:
@src/services/userService.ts のテストを書いて。
既存のテスト @src/services/__tests__/authService.test.ts のスタイルに合わせること。
Vitestを使い、モックはvi.mockを使用して。pytestの場合:
@src/services/user_service.py のテストを書いて。
pytestを使い、fixtureでテストデータを管理すること。
外部APIの呼び出しはrespxでモックして。「既存のテスト @path/to/existing.test.ts のスタイルに合わせて」と指示すると、プロジェクトの規約に沿ったテストが生成されます。Claude Codeは参照ファイルを読んでパターンを学習します。
テスト観点を具体的に指定する
テストの品質を高めるために、検証したい観点を具体的に伝えましょう。
@src/services/userService.ts のcreateUser関数のテストを書いて。
以下の観点をカバーすること:
- 正常系: 有効な入力でユーザーが作成される
- バリデーション: メールアドレスの形式が不正な場合
- バリデーション: 必須フィールドが欠けている場合
- 重複チェック: 既存のメールアドレスで作成しようとした場合
- エラーハンドリング: DB接続エラーが発生した場合
- 境界値: 名前が最大文字数の場合
テスト実行後にすべてパスすることを確認して生成されたテストを実行して確認する
テストを生成したら、必ず実行して結果を確認しましょう。Claude Codeに実行まで依頼するのがスムーズです。
生成したテストを実行して、失敗があれば修正してClaude Codeはテストを実行し、失敗があれば原因を分析して修正してくれます。この「生成 → 実行 → 修正」のループを自動で回してくれるのが大きな強みです。
効果的な指示のコツ
境界値テストを明示的に依頼する
Claude Codeはデフォルトでは「よくある正常系」のテストを多く生成しがちです。品質の高いテストスイートにするには、境界値やエッジケースを明示的にリクエストしましょう。
calculateDiscount関数のテストに、以下の境界値テストを追加して:
- 割引率が0%の場合
- 割引率が100%の場合
- 金額が0円の場合
- 金額が負の値の場合
- 小数点以下の端数処理モック対象を明確にする
外部依存のモック指定があいまいだと、テストの信頼性が下がります。何をモックして何をモックしないかを明確にしましょう。
テストを書くにあたっての方針:
- データベースアクセス(repository層)はモックする
- バリデーションロジックはモックしない(実際の検証を通す)
- 外部API(Stripe)はモックする
- 日時は固定値(2026-01-01T00:00:00Z)を使うテスト名を日本語で書く
テスト名の命名規則を指定しておくと、一貫性のあるテストスイートになります。
テスト名は日本語で、以下の形式で書いて:
「〜の場合、〜すること」
例:
- "メールアドレスが空の場合、バリデーションエラーを返すこと"
- "正常なリクエストの場合、ユーザーを作成して201を返すこと"実践例: 関数のテスト生成フロー
実際にClaude Codeでテストを生成する一連の流れを見てみましょう。
対象コード
以下のようなユーザー登録関数があるとします。
// src/services/userService.ts
export async function registerUser(input: RegisterInput): Promise<User> {
// メールアドレスのバリデーション
if (!isValidEmail(input.email)) {
throw new ValidationError("メールアドレスの形式が不正です");
}
// 重複チェック
const existing = await userRepository.findByEmail(input.email);
if (existing) {
throw new ConflictError("このメールアドレスは既に登録されています");
}
// パスワードのハッシュ化
const hashedPassword = await hashPassword(input.password);
// ユーザー作成
return await userRepository.create({
email: input.email,
name: input.name,
password: hashedPassword,
});
}プロンプト例
@src/services/userService.ts のregisterUser関数のテストを書いて。
方針:
- Vitestを使用
- userRepositoryはvi.mockでモック
- hashPasswordもモック(戻り値は "hashed_password" 固定)
- isValidEmailはモックしない(実際の検証ロジックを通す)
テストケース:
1. 正常系: 有効な入力でユーザーが作成される
2. メールアドレスが不正な場合にValidationErrorが投げられる
3. メールアドレスが既に登録済みの場合にConflictErrorが投げられる
4. repositoryのcreate呼び出しにハッシュ化されたパスワードが渡される
テストを書いたら実行して、すべてパスすることを確認して一度にすべてのテストケースを網羅しようとせず、まず基本的なテストを生成してパスさせてから、「エッジケースを追加して」「エラーパターンのテストを充実させて」と段階的に拡充していくのが効果的です。
サブエージェントでテストの品質をチェックする
生成したテストが実装をきちんと検証できているか心配な場合は、サブエージェントにレビューさせましょう。
サブエージェントを使って、生成したテストコードをレビューして。
以下の観点でチェックして:
- テストが実装の重要なロジックを検証しているか
- モックの設定が正しいか
- テストが実装の変更に脆くないか(実装詳細に依存しすぎていないか)応用テクニック
CLAUDE.mdにテスト方針を記載する
テスト生成のたびに同じ指示を繰り返さなくて済むよう、プロジェクトのCLAUDE.mdにテスト方針を書いておきましょう。
## テスト方針
- テストフレームワーク: Vitest
- テストファイルの配置: 対象ファイルと同じディレクトリに `.test.ts`
- テスト名: 日本語で「〜の場合、〜すること」の形式
- モック方針: repository層はモック、ビジネスロジックはモックしない
- テスト実行: `npm run test -- --run src/path/to/file.test.ts`ファンアウトで大量のテストを一括生成する
テストがまったく書かれていないプロジェクトの場合、非対話モードでファイルごとにテストを一括生成できます。
for file in $(find src/services -name "*.ts" ! -name "*.test.ts"); do
claude -p "このファイルのテストを書いて、実行してパスすることを確認して: $file" \
--allowedTools "Edit,Bash(npm run test *)"
done一括生成したテストは品質にばらつきが出やすいです。生成後に /code-review でまとめてチェックするか、重要なモジュールについては個別にレビューすることをおすすめします。
まとめ
- テスト生成はフレームワーク・モック方針・テスト観点を具体的に指示するのがコツ
- 境界値・エラーケースは明示的にリクエストしないと生成されにくい
- 「生成 → 実行 → 修正」のループをClaude Codeに任せることで効率的にテストを整備できる
- テスト方針はCLAUDE.mdに書いておくと毎回の指示が楽になる
- 既存テストファイルを参照させると、プロジェクトの規約に沿ったテストが生成される