結論:Claude Code は「テストを書かせる」のではなく「テストで自分の実装を検証させる」道具として使うと、品質が一段上がる。
- ① 既存コードのテスト生成:未カバー関数を洗い出し、正常系・異常系・境界値を pytest / Jest / Vitest の既存パターンに合わせて自動生成する。
- ② TDD(テスト先行):Red(失敗するテスト)→ Green(最小実装)→ Refactor を Claude Code に回させ、各ステップで人がレビューする。
- ③ エッジケースの洗い出し:境界値・エラー条件・想定外入力を Claude に列挙させ、抜けを埋める。
対象読者:pytest / Jest / Vitest / JUnit などで日常的にテストを書く開発者・エンジニア・テックリード。今日できること:手元の1関数で「テスト生成 → 失敗確認 → 実装 → 全パス」のループを1周回す。
※本記事は2026年6月時点の Claude Code の挙動・公式ドキュメントに基づく。バージョンや仕様は更新されるため、最終的な挙動は各自の環境で確認してほしい。
「テストは書いた方がいいのは分かってる。でも、既存コードに後付けでテストを書くのは正直しんどいし、TDDも『理想は分かるけど現場で回らない』で止まってる」——これ、自分も長らくそうでした。テストを書く時間がボトルネックになって、結局あと回しになる。
Claude Code を使い始めて変わったのは、テストを書く作業そのものをエージェントに任せて、自分は「テストが正しいか」「実装が要件を満たすか」のレビューに集中できるようになった点です。ただし、ここには大きな落とし穴があります。AIが生成したテストを無検証で信じると、「常にパスするだけの空テスト」が量産されて、カバレッジの数字だけ上がって品質はむしろ下がる。この記事では、その罠を避けながら ①テスト自動生成 ②TDD ③エッジケース洗い出し を実務でどう回すかを、具体的なプロンプトとコード例つきで解説します。

Claude Code でテストを書く前に押さえる「検証ループ」の考え方
Claude Code の公式ベストプラクティスには “Give Claude a way to verify its work”(Claudeに自分の仕事を検証する手段を与えよ)という原則があります。要点はこうです。
Claude は「作業が終わったように見えた」時点で止まる。検証手段がなければ「終わったように見える」が唯一のシグナルになり、あなたが検証ループそのものになってしまう。パス/フェイルを返すもの(テスト、ビルドの終了コード、リンター)を渡せば、ループは自動で閉じる。(Claude Code 公式ドキュメント「Best practices」より要約)
テストはこの「検証手段」の代表格です。つまり Claude Code におけるテストの本質的な価値は、カバレッジを稼ぐことではなく、Claude 自身が実装の正しさを判定できるようにすることにあります。この前提を持っているかどうかで、テスト自動生成の使い方がまったく変わります。
もう1つ重要なのが、公式が「よくある失敗パターン」として挙げている “The trust-then-verify gap”(信頼してから検証するギャップ)です。「Claudeが一見もっともらしい実装を出すが、エッジケースを処理できていない」——その対策が「常に検証手段(テスト・スクリプト・スクリーンショット)を用意せよ。検証できないなら出荷するな」。AIが書いたテストもコードも、人が検証する前提で扱うのが大原則です。
① 既存コードのユニットテストを自動生成する手順
まずは一番ニーズの多い「既存コードに後付けでテストを書く」ケース。公式ドキュメントの「Work with tests」レシピに沿って、4ステップで進めます。いきなり「全部にテスト書いて」と投げず、未カバー箇所の特定 → 雛形生成 → ケース追加 → 実行・修正の順で刻むのがコツです。
- 未カバーの関数を特定する。「どのコードにテストがないか」を Claude に洗い出させる。テストランナーのカバレッジレポートがあれば、それを読ませると精度が上がる。
- テストの雛形(scaffolding)を生成させる。このとき「既存のテストファイルのスタイルに合わせて」と必ず指定する。Claude は既存テストを読んでフレームワーク・アサーションの書き方を踏襲する。
- 意味のあるケースを足す。正常系だけでなく、異常系・境界値・想定外入力を明示的に列挙させる。
- 実行して失敗を直す。「テストを実行して、失敗があれば直して」まで一気に指示し、Claude にループを閉じさせる。
具体的なプロンプトはこう書きます。対象ファイル・観点・フレームワークを明示するのがポイントです。
@src/services/pricing.py のうち、テストが無い関数を洗い出して。
そのあと calculate_discount() の pytest ユニットテストを生成して。
- 正常系:割引率10%・50%が正しく適用される
- 異常系:割引率が負・100超のときに ValueError
- 境界値:0%、100%、入力が0円のとき
既存の tests/ のスタイルに合わせて、テストを実行して失敗があれば直して。
生成されるテストのイメージ(pytest の例)。parametrize で境界値をまとめ、pytest.raises で異常系を検証する、ごく標準的な形になります。
import pytest
from src.services.pricing import calculate_discount
@pytest.mark.parametrize("price, rate, expected", [
(1000, 10, 900), # 正常系
(1000, 50, 500), # 正常系
(1000, 0, 1000), # 境界値:割引なし
(1000, 100, 0), # 境界値:全額割引
(0, 50, 0), # 境界値:0円入力
])
def test_calculate_discount_valid(price, rate, expected):
assert calculate_discount(price, rate) == expected
@pytest.mark.parametrize("rate", [-1, 101, 200])
def test_calculate_discount_invalid_rate(rate):
with pytest.raises(ValueError):
calculate_discount(1000, rate)
ここで必ずやるべきなのが「テストを読む」レビューです。Claude が assert calculate_discount(...) == calculate_discount(...) のような自己言及で常にパスするテストや、期待値を実装の出力に合わせただけの「テストのための実装追認」を書いていないか確認します。期待値は仕様から導くものであって、現在の実装の出力をコピーしたものであってはいけません。
② TDD(Red→Green→Refactor)を Claude Code で回す
TDD(テスト駆動開発)は、Kent Beck らが提唱した「実装の前にテストを書く」開発手法です。Martin Fowler の定義どおり、サイクルは3ステップ。
- Red:これから作る機能の失敗するテストを1つ書く。まだ実装がないので当然落ちる。
- Green:そのテストを通す最小限の実装を書く。きれいさは後回し、まず通す。
- Refactor:テストが緑のまま、重複を消し設計を整える。
Claude Code で TDD を回すときの肝は、「Red のテストが正しく失敗することを人が確認してから Green に進む」ことです。これを飛ばすと、テストが間違っていて常にパスしているのに気づかないまま実装が進む、という最悪のパターンになります。公式ドキュメントも「Explore → Plan → Implement → Commit」の Implement フェーズで “write tests for the callback handler, run the test suite and fix any failures”(コールバックハンドラのテストを書き、テストスイートを実行して失敗を直す)という流れを推奨しています。
実際の進め方を、メール検証関数 validateEmail を題材に Jest で示します。まず Red のテストだけを書かせます。
これから validateEmail(email) を TDD で実装する。
まず Red ステップとして、まだ実装が無い前提で失敗する Jest テストを書いて。
- [email protected] は true
- invalid は false(@が無い)
- [email protected] は false(ドメイン不正)
- 空文字は false
実装コードはまだ書かないで。テストファイルだけ作って。
// validateEmail.test.js
import { validateEmail } from "./validateEmail";
describe("validateEmail", () => {
test.each([
["[email protected]", true],
["invalid", false],
["[email protected]", false],
["", false],
])("validateEmail(%s) === %s", (input, expected) => {
expect(validateEmail(input)).toBe(expected);
});
});
ここで npx jest を実行し、「モジュールが見つからない/関数が無い」で全部 Red になることを自分の目で確認します。期待どおり落ちたら、Green に進みます。
テストが正しく失敗するのを確認した。
次に Green ステップ。validateEmail を実装して、
さっきのテストが全部通る「最小限のコード」を書いて。
テストを実行してパスすることを確認して、結果を見せて。
Green が通ったら Refactor。「テストを緑に保ったまま、正規表現を共通化する/可読性を上げる」と指示し、リファクタ後にもう一度テストを走らせて緑を維持できているか確認します。この「テストが安全網になっているから安心して構造を変えられる」状態こそ TDD の本丸です。
Claude Code にはテストが緑になるまで止まらないようにする仕組みもあります。公式の /goal 条件や Stop hook を使うと、別の評価器が毎ターン後にテストを再チェックし、パスするまで Claude が作業を続けます。長時間の自律実行で「テスト緑」を完了条件にしたいときに有効です。
③ テストの不足・エッジケースを Claude に洗い出させる
テストの一番の難所は「自分が思いつかなかったケース」です。ここは Claude のコード読解が効きます。公式ドキュメントも「網羅性のために、見落としているエッジケースを Claude に挙げさせよ。Claude はコードパスを分析し、エラー条件・境界値・想定外入力を提案できる」としています。
既存のテストファイルと対象コードの両方を読ませて、「足りていないケース」だけを列挙させるのが効率的です。
@src/services/pricing.py と @tests/test_pricing.py を読んで。
既存テストでカバーされていないエッジケースを列挙して。
特に以下の観点で抜けを探して:
- 境界値(最小・最大・0・空)
- 型・null/None・不正な型の入力
- 並行・状態依存(同じ関数を続けて呼んだときの副作用)
- エラー時の挙動(例外の種類・メッセージ)
コードは変えず、追加すべきテストケースの一覧だけ出して。
列挙された候補を人がトリアージします。すべてをテスト化すると、起こり得ない条件のための過剰なテストで保守コストが膨らむ(公式が警告する「over-engineering」)ので、「正しさや要件に影響するもの」だけを採用するのが現実解です。採用を決めたら、改めて「このケースのテストを既存スタイルで追加して実行して」と指示します。
さらに堅くしたいなら、別セッション(または subagent)にレビューさせるのが効きます。実装したセッションと違う文脈のモデルに「この diff とテストを、要件に対して抜けが無いか確認して。スタイルの好みではなく、正しさに関わる抜けだけ報告して」と投げると、自分が書いたコードへのバイアスがかからない第三者チェックになります。公式の Writer/Reviewer パターン(一方がテストを書き、もう一方がそれを通すコードを書く)も同じ発想です。
CI でテストを自動実行し、品質ゲートにする
テストは「ローカルで1回通った」で終わらせず、CI に組み込んで初めて品質ゲートになります。Claude Code は claude -p の非対話モードで CI・pre-commit・バッチ処理に組み込めます。GitHub Actions の例で、テストを実行し、落ちたら Claude に原因分析させる流れを示します。
- 通常のテストステップを置く。まず
pytest/jest/vitestをそのまま CI で走らせ、失敗を検知する。 - 失敗時に Claude を非対話で呼ぶ。テスト出力を渡して原因と修正案を出させる(自動コミットまでさせるかは権限設計しだい)。
- 権限を絞る。
--allowedToolsで実行できるツールを限定し、無人実行の暴走を防ぐ。
# .github/workflows/test.yml(抜粋)
- name: Run tests
run: pytest -q
- name: Explain failures with Claude (on failure)
if: failure()
run: |
pytest -q 2>&1 | claude -p \
"このテスト失敗の原因を特定して。根本原因を指摘し、症状を握りつぶさない修正案を出して。" \
--allowedTools "Read,Grep"
ローカルなら pre-commit hook で「コミット前にテスト実行、落ちたら止める」を入れておくと、壊れたコードがそもそもリポジトリに入りません。Claude Code 自身の Stop hook を使えば、エージェントのターン終了をテストパスでゲートすることもできます。いずれにせよ、「人が見ていない時間にこそテストが品質を守る」という設計思想は共通です。
よくある失敗パターンと回避策
Claude Code でのテスト運用でハマりがちな点を、❌(やりがち)/⭕(こうする)形式でまとめます。
失敗1:AIが書いたテストを無検証でマージする
❌ 「テスト書いといて」→ 緑になった → そのままマージ。実は期待値が実装の出力に合わせてあるだけで、何も保証していない。
⭕ テストを必ず読む。Red のテストは「正しく失敗すること」を、Green は「期待値が仕様から導かれていること」を人が確認する。期待値の根拠を Claude に説明させるのも有効。
失敗2:カバレッジの数字だけを目標にする
❌ 「カバレッジ100%にして」→ 全行を通すだけのアサーション無し・自明テストが量産され、保守だけ重くなる。
⭕ カバレッジは副産物と捉え、「この関数の重要な振る舞い・エッジケース」を起点に必要なテストを決める。起こり得ない条件のテストは作らない。
失敗3:Red を飛ばして Green から始める
❌ 実装とテストを同時に書かせる → テストが間違っていても、実装が間違っていても、両方つじつまが合って緑になり、バグが残る。
⭕ TDD では必ず Red を1回挟み、「テストが期待どおり失敗する」ことを確認してから実装に進む。
失敗4:1プロンプトに巨大なタスクを詰め込む
❌ 「このモジュール全部にテスト書いて」→ 文脈が膨れて精度が落ち、雑なテストが大量に出る。
⭕ 関数単位・観点単位に刻む。投資対効果の高い中核ロジックから着手し、1周ごとにレビューする。
まとめ:テストは「書かせる」より「検証させる」
Claude Code でのテストは、カバレッジ稼ぎの作業代行ではなく、実装の正しさを Claude 自身に判定させるための検証ループとして設計すると効果が最大化します。①既存コードのテスト生成は「未カバー特定 → 雛形 → ケース追加 → 実行修正」、②TDD は「Red を人が確認 → Green → Refactor」、③エッジケースは「Claude に列挙させて人がトリアージ」。そして CI・hook で無人時間の品質ゲートにする。共通するのは「AIが書いたテストもコードも、人が検証する前提で扱う」という一点です。まずは手元の1関数で、テスト生成から全パスまでのループを1周回してみてください。
関連記事
- Claude Code Hooks実践ガイド|整形・通知の自動化【2026】 — hook で整形・通知・テスト実行を自動化する方法。本記事の「テストを品質ゲートにする」と相性がよい。
- Claude Code で CI/CD パイプライン自動化【2026】 — テスト実行を含む CI/CD への組み込み方を詳述。
- Claude Code サブエージェント並列実行ガイド — テストのレビューを別文脈の subagent に任せる Writer/Reviewer パターンの実装に。
- CI 失敗を Claude Code で自動修正する5ステップ — CI でテストが落ちたときの自動修正フローの実例。
出典
- Best practices for Claude Code — Anthropic(Claude Code 公式ドキュメント)
- Common workflows(Work with tests レシピ)— Claude Code 公式ドキュメント
- Test Driven Development — Martin Fowler
- pytest 公式ドキュメント
- Jest 公式ドキュメント(Getting Started)
- Vitest 公式ドキュメント(Guide)
著者:佐藤傑(さとう・すぐる) 株式会社Uravation 代表取締役。X(@SuguruKun_ai)フォロワー約10万人。100社以上の企業向けAI研修・導入支援を実施。著書『AIエージェント仕事術』(SBクリエイティブ)。SoftBank IT連載を7回執筆。