Claude Codeでテストを書かせる実践手順
Claude Codeに既存コードのテストを書かせる手順を、カバレッジの薄い箇所の特定からエッジケースの追加、実行して直すところまでまとめます。
Claude Codeに既存コードのテストを書かせるとき、効いてくるのは進める順番です。カバレッジの薄い箇所を特定させ、既存のテストパターンに沿った雛形を作らせ、そのあとでエッジケースを積み増す。この順で進めると、書きっぱなしで終わらず実行して直すところまで一気通貫で回せます。同じ順序立ては、Locust負荷テストのシナリオ設計にも応用できます(Claude CodeでLocust負荷テストのシナリオを書く手順)。書いたテストが実際に効くかは、Claude CodeでStrykerのミューテーションテストを回す手順で確かめられます。
Claude Codeにテストを書かせるとはどういう作業か
ここで扱うのは、すでに動いているコードに後からテストを足す作業です。実装より先にテストを置くテスト駆動開発とは狙いが異なります。テスト駆動開発は「これから作る仕様」を先に固定するのに対し、こちらは「いま動いている挙動」をテストの形で記録します。テスト駆動開発の型そのものはClaude Codeでテスト駆動開発を回す手順にまとめているので、本稿では既存コードへの後付けに絞ります。複数タスクにまたがってRED→GREENのTDDを自動で回す仕組みはcc-sddでClaude Codeの仕様駆動開発を実践するで扱っています。
Claude Codeはこの作業を任せると、既存のテストファイルを読んでスタイル・フレームワーク・アサーションの書き方を確認したうえでテストを書きます。指示する側が「何を確認したいか」を具体的に伝えると、狙いに沿ったテストになりやすくなります。逆に「テストを増やして」とだけ伝えると、対象の絞り込みから優先順位付けまでをClaude Code任せにすることになり、本当に必要な箇所が後回しになることがあります。
始める前に確認すること
テストを書かせる作業は、テスト実行と編集の往復が何十回も続きます。その間ずっと許可の確認が出ると流れが止まるので、着手前に3つだけ整えます。
着手前の3つの下準備
- 1
テストを1コマンドで走らせる
npm testでもpytest -qでも構いません。引数なしで走って合否を返す形にしておくと、指示文に手順を書かずに済みます。 - 2
権限モードを選ぶ
v2.1.283以降の対話セッションは、auto modeが利用可能なら既定でそのモードで始まります。v2.1.283より前でも、Pro・Max・Teamプランなら同じくauto modeで始まります。
Shift+Tabでモードを切り替えられ、acceptEditsにするとファイル編集の確認が消えます。auto modeが使えない環境ではManualで始まるので、確認が多いと感じたら次の許可ルールを足します。 - 3
テストコマンドだけ許可する
許可ルールは末尾の
*でコマンド全体を受けます。Bash(npm run *)とBash(npm run:*)は同じ意味で、npm run test --watchのような派生も通ります。
許可ルールは、次のように設定ファイルのallowに書きます。
{
"permissions": {
"allow": ["Bash(npm test)", "Bash(npm run test *)"]
}
}Bash(npm test)は完全一致なので、引数を足したnpm test -- --watchは通りません。オプションを付けて走らせたいなら、末尾に*を付けた形にします。
CIなど人が画面の前にいない場面では、--permission-mode dontAskと--allowedToolsを組み合わせる形が公式の例に載っています。許可リストにないコマンドは確認なしで拒否されるため、テストコマンド以外に手が伸びません。--allowedToolsはカンマか空白区切りで複数指定でき、v2.1.285のclaude --helpでは"Bash(git *) Edit"という書き方が例示されています。
claude -p "run the test suite" --permission-mode dontAsk --allowedTools "Bash(npm test)" "Read"手順1: カバレッジの薄い箇所を特定する
最初に、どこにテストが無いかをClaude Code自身に洗い出させます。ファイル名を1つ指定して聞くと、対象範囲が絞られて回答が具体的になります。
NotificationsService.swiftでテストされていない関数を見つけて対象がファイル単位で分からない場合は、機能名やモジュール名で聞いても構いません。ただし対象が広すぎると調査だけでコンテキストを消費するため、最初は1ファイルか1モジュールに絞るのが安全です。複数の対象を並行して洗い出したいときは、対象ごとに質問を分けて実行し、結果を都度確認してから次に進みます。
手順2: 既存パターンに沿った雛形を作らせる
対象が定まったら、テストの雛形をClaude Codeに生成させます。ここでClaude Codeは既存のテストファイルを読み、同じフレームワーク・同じアサーションの書き方に合わせてコードを書きます。プロジェクトに既存のテストが1つもない場合は、先にフレームワークとアサーションの方針を指示してから任せます。
通知サービスのテストを追加してこの段階で生成されるのは、正常系を中心にした最初の一群です。ここで満足せず、次の手順でエッジケースを足すところまでを1セットの作業として扱います。生成された雛形をひと通り眺め、意図と違うアサーションが混ざっていないかをここで確認しておくと、後段の修正が減ります。
手順3: エッジケースを追加させる
正常系だけのテストは、リファクタリング時の安全網としては不十分です。境界値・異常系・想定外の入力といった、書く側が見落としやすいケースを追加で聞き出します。
通知サービスのエッジケースのテストケースを追加してClaude Codeはコードのパス(条件分岐や早期returnの箇所)を解析し、エラー条件・境界値・想定外の入力に対するテストを提案します。人間が実装するときに見落としがちな分岐ほど、この段階で拾える価値が大きくなります。同様の見落としを自律的に探索する手法はClaudeがProperty-Based TestingでPythonのバグを見つける仕組みで扱っています。「エッジケースを追加して」だけでなく、「nullが渡された場合」「タイムアウトした場合」のように具体例を添えると、狙った分岐を確実に拾わせられます。
手順4: テストを実行して失敗を直させる
テストを書かせたら、必ず実行させて結果を読ませます。書いた本人に実行と修正まで任せることで、構文エラーやアサーションのずれをその場で潰せます。
新しく追加したテストを実行して、失敗があれば直して失敗が残ったときは、直す先をまず決めます。
失敗したとき、直すのはどちらか
テストを直す
構文エラー、存在しない関数の呼び出し、期待値の書き間違いなど、テストコード自体が誤っている場合です。Claude Codeに直させて再実行します。
実装を直す
関数が本来こう動くべきという期待とテストが一致していて、実装が外れている場合です。テストを実装に合わせて直すとバグを隠すだけのテストになるため、期待する挙動を先に言葉で確認します。
判断に迷ったら、その関数が本来どう動くべきかをClaude Codeに説明させ、自分の認識と合っているかを確かめてから、直す先を決めます。
よくあるつまずき
テストファイルが1つも無い状態から始めると方針がぶれる
参照できる既存パターンが無いため、フレームワークの選定やアサーションの書き方を毎回聞き直すことになります。最初の数本は人間が方針を決めて書き、以降をClaude Codeに引き継ぐほうが安定します。
「テストを追加して」とだけ伝えると正常系に寄る
雛形とエッジケースは別ターンで指示し、それぞれの結果を確認してから次に進みます。
カバレッジ計測ツールが無いプロジェクトでは「薄い箇所」の判定が曖昧になる
手順1の「テストされていない関数を見つけて」は静的な読み取りに頼っているため、実行時のパスカバレッジまでは保証しません。カバレッジレポートを出力できる環境なら、レポートのファイルパスを渡して優先順位をつけさせるとより正確です。
大きなモジュールをまとめて対象にすると調査でコンテキストを使い切る
調査対象が広いと感じたら、サブエージェントに調査だけを委任する方法もあります。カバレッジの棚卸しを別のコンテキストで走らせ、実装のメインセッションには結果だけを持ち帰らせると、会話が調査の出力で埋まりません。
既存コードにテストが無い理由が「壊れやすいから」であることもある
密結合していて1つの関数を差し替えるだけで広範囲に影響が及ぶようなコードは、テストを書く前にまず構造をほぐす必要があります。テストを足す前に軽くリファクタリングが必要なケースでは、テストが無いコードのリファクタリング手順を先に踏んでから本稿の手順に戻るほうが安全です。
よくある質問
モックやスタブの扱いはどう指示すればいいですか
既存のテストファイルにモックの使い方があれば、Claude Codeはそのパターンを踏襲します。プロジェクトに前例が無い場合は、「外部APIの呼び出しはモックに置き換えて」のように扱い方を明示しておくと、実際にネットワークへ到達するテストが混ざるのを防げます。
許可ルールを足したのに、確認が消えません
ルールの書き方が原因のことがあります。Bash(npm test)は完全一致なので、npm test -- --coverageのように引数が付くと別のコマンド扱いになり、確認が出ます。引数を許すならBash(npm test *)と書きます。Bash(npm*)のようにスペースなしの*を付けると、npmxのような別コマンドまで一致するため、スペースを入れた形が安全です。
テストカバレッジは何%を目指せばいいですか
数値目標を決めてClaude Codeに丸投げすると、意味の薄いテストで数値だけを埋める結果になりがちです。カバレッジ率そのものを目的にせず、「壊れたら困る挙動から優先してテストする」という基準で対象を選ぶほうが、後々の安全網として機能します。
統合テストとユニットテストのどちらを書かせるべきですか
対象の粒度による部分が大きいですが、まず個々の関数やメソッド単位のユニットテストから始めると、失敗時の原因特定が早くなります。複数のモジュールをまたぐ処理は、ユニットテストである程度の安全網ができたあとに統合テストで補うと、手戻りが少なくなります。既存のテストディレクトリにユニットテストと統合テストの区分がある場合は、その区分をClaude Codeに伝えると、どちらの層に書くべきかを判断させやすくなります。
まとめ
最初の1回は1ファイルに絞り、着手前の許可ルールと手順ごとの確認を試してから対象を広げると、どこで確認が止まるかを先に潰せます。同じ「条件を先に固めてから生成させる」進め方は、Claude Codeでk6の負荷テストスクリプトを作成する手順のような負荷テストスクリプトの生成でも活きます。