AIはテストを書くのは得意、でも「何が正しいか」を決めるのは苦手
はじめに
Claude Code や Cursor、Copilot を使っていると、テストコードがあっという間に生成されることに驚きます。「テストを書いて」と頼めば、それらしいテストが大量に出てきます。
しかし、ある失敗をきっかけに気づきました。
AIはテストを「書く」のは得意ですが、「何が正しいか」を決めるのは苦手です。
この記事では、その違いがなぜ重要なのか、そして私がどうAIとテストを分担しているかを書きます。
きっかけになった失敗
ある機能の実装とテストを、同じAIに続けてお願いしました。実装を生成させ、その流れで「この実装のテストを書いて」と頼んだのです。
結果、テストはすべてグリーンで通りました。安心してマージしたのですが、後でバグが見つかりました。
原因はこうです。
- 実装にはロジックの誤りがあった
- AIはその間違った実装に合わせてテストの期待値を書いた
- だから実装もテストも、お互いに「正しい」と言い合って両方通ってしまった
💡 間違った答案を、間違った模範解答で採点していたようなものです。両方が同じ勘違いをしているので、永遠に気づけません。
なぜこうなるのか
ここに、AIとテストの本質的な問題があります。
テストには2つの異なる作業が含まれています。
| 作業 | 内容 | AIの得意度 |
|---|---|---|
| テストを書く | テストの構造・記法・モックを用意する | とても得意 |
| 期待値を決める | 「正しい結果は何か」を判断する | 苦手 |
AIは前者、つまりテストの形を作ることは非常に得意です。構文も整っているし、モックの組み方も知っています。
しかし後者、「この入力に対する正しい出力は何か」 を決めるのは、本来そのコードの仕様を理解している人間の仕事です。AIは仕様の真の意図を知らないので、目の前のコードの挙動をなぞって期待値を埋めがちです。
挙動をなぞった期待値は、実装が間違っていればその間違いごとコピーしてしまいます。
テストの本来の役割を思い出す
そもそもテストは何のためにあるのでしょうか。
テストの価値は「コードが動くこと」を確認することではありません。「コードが意図した通りに動くこと」を確認することです。
- 動くかどうか → 実行すればわかる
- 意図通りかどうか → 意図を知っている人にしかわからない
AIに期待値まで任せると、この「意図」の部分が抜け落ちます。テストはたくさんあるのに、本当に守りたいことを守っていない状態になります。
私の分担方法
この失敗以来、私はテストの作業を分けるようにしました。
1. 観点出しはAIに任せる
「この関数に対して、テストすべきケースを洗い出して」と頼みます。
AIはここで力を発揮します。自分では見落としがちな異常系を挙げてくれるからです。
- 空の入力
- 上限・下限の値
- 想定外の型
- 同時実行や重複
「何をテストすべきか」のリスト作りは、AIの知識量が活きる場面です。
2. 期待値は自分で書く
洗い出されたケースに対して、「正しい結果は何か」は自分で決めます。
ここを人間がやることで、実装が間違っていればテストが落ちる、という本来の関係を取り戻せます。実装とテストが別の視点から作られるからこそ、矛盾が表面化します。
3. 実装とテストを同じ流れで生成させない
これが一番大事かもしれません。実装を書いたAIにそのままテストを書かせると、同じ勘違いを共有します。
- 実装とテストの生成を分ける
- あるいは期待値だけは必ず人間が書く
こうするだけで、「両方グリーンなのに間違っている」事故はかなり減りました。
まとめ
- AIはテストを書くのは得意だが、何が正しいかを決めるのは苦手
- 実装とテストを同じAIに続けて書かせると、間違いごと一致して両方通る
- テストの価値は「動くこと」ではなく「意図通りに動くこと」の確認にある
- だから 観点出しはAIに、期待値は人間に 分けるのが有効
AIによってテストを書くコストは劇的に下がりました。だからこそ、人間が担うべき部分が「何が正しいかを決めること」に絞られてきたのだと思います。
テストを書く速さに安心せず、「この期待値は本当に正しいか」を自分の頭で一度問い直す。これがAI時代のテストとの付き合い方だと感じています。