
AIのテストはカバレッジが高い|意味のあるテストとの差
「カバレッジ90%です」——そう報告したのに、なぜか胸を張りきれない。 AIにテストを書かせたら、あっという間に数字が上がった。緑のバーが並んで、見た目はきれいです。でも、いざこのコードを本番に出すと思うと、どこか落ち着かない。「このテスト、本当にバグを見つけてくれるんだろうか」と。
その違和感は、気のせいではありません。 カバレッジが高いことと、テストが意味を持つことは、別の話だからです。AIは「行を通過するテスト」を作るのは得意ですが、「壊れたらちゃんと落ちるテスト」を作れているかは、また別。数字だけ見ていると、この差が見えなくなります。
この記事では、その差の正体を分解して、カバレッジの数字に頼りすぎずに「意味のあるテスト」を見分ける観点を整理します。AIを責める話でも、カバレッジを否定する話でもありません。数字を味方にしつつ、抜けやすい所を人が押さえる——その分担を、一緒に考えていきます。
結論:カバレッジは「コードのどこを通ったか」を測る指標で、「その振る舞いが正しいか」は測っていません。だから確認したいのは3点。①アサーション(検証)が実際に意味のある値をチェックしているか(呼ぶだけで通るテストになっていないか)、②わざとコードを壊したときテストが落ちるか(ミューテーションの発想)、③境界・異常系・仕様の意図がカバーされているか。この3つを人が押さえれば、AIが上げた数字は「見せかけ」から「頼れる安全網」に変わります。
カバレッジが高いのに不安なのは、あなたの感覚が鈍いからではありません。 むしろ、その違和感に気づけている時点で、数字の裏側を見ようとしている証拠です。今日はその違和感を、具体的なチェックの形に変えていきましょう。
カバレッジが測っているもの、測っていないもの

まず、言葉を整理します。 カバレッジ(コードカバレッジ)とは、テストを実行したときに「コードのどの行・分岐が通過したか」の割合です。90%なら、コードの9割の行がテスト中に一度は実行された、という意味になります。
ここで大事なのは、カバレッジが測っているのは「通ったかどうか」だけだということ。 その行を通ったときに、結果が正しいかを確かめたかは、カバレッジには含まれません。極端な話、こういうテストでもカバレッジは上がります。
// これでもカバレッジは上がってしまう
test("calculatePrice を呼ぶ", () => {
calculatePrice(100, 0.1); // 呼んだ。以上。
// 戻り値を一切チェックしていない
});
このテストは calculatePrice の中の行を通過するので、カバレッジ上は「テスト済み」に見えます。でも、戻り値が110なのか、0なのか、NaNなのかは一切確かめていない。つまり、この関数が壊れても、このテストは何も教えてくれません。
カバレッジが高いのに不安になるのは、こういう「通っているだけのテスト」が混じっているからです。 数字は「どれだけ通ったか」しか語りません。「どれだけ確かめたか」は、別の目で見る必要があります。
AIのテストで起きやすい「3つの見せかけ」

AIが生成したテストを開いたとき、注意して見たいパターンが3つあります。どれも、カバレッジの数字には表れません。
1. 「呼ぶだけ」テスト(アサーションが弱い・無い)
さっきの例のように、関数を呼ぶけれど戻り値や状態を検証していない、あるいは検証がとても緩いテストです。 expect(result).toBeDefined()(値が存在すること)だけで終わっているものも、これに近い。値が「何か」であればいいので、間違った値が返っても通ってしまいます。AIは「テストらしい形」を作るのは上手ですが、何を検証すべきかの意図までは、こちらが伝えないと薄くなりがちです。
2. 「実装をなぞっただけ」テスト
テストが、実装コードと同じ計算をそのまま書いてしまうパターンです。 たとえば実装が a 1.1 なら、テストの期待値も a 1.1 と書いてしまう。これだと、実装のバグ(本当は 1.08 であるべき等)がそのままテストにもコピーされ、間違っていても両方一致して通ります。テストは「実装が正しいこと」ではなく「仕様が満たされていること」を確かめるものなので、期待値は仕様から決めた具体的な数字(110 など)で書きたい所です。
3. 「幸せな道(ハッピーパス)だけ」テスト
正常に動くケースはテストされているのに、異常系や境界がごっそり抜けているパターンです。 入力が正しいときのテストは書きやすく、AIも量産します。でも実際にバグが潜むのは、空文字・0・マイナス・null・上限超え・同時実行といった端っこ。ここが抜けていても、正常系だけでカバレッジはそれなりに上がるので、数字では気づけません。境界・異常系の洗い出しは境界値・異常系をAIに考えさせて漏れを減らす手順にも整理しています。
この3つに共通するのは、「テストは存在するのに、壊れても気づけない」ということ。 カバレッジは「テストが存在するか」までしか見ていないので、この中身の弱さは、人が開いて確かめるしかありません。
「意味のあるテスト」を見分ける一番シンプルな問い
では、どうやって見分けるか。 難しい理屈より先に、いちばん効く問いをひとつ渡します。
「このテストが通っている状態で、わざと実装を1か所壊したら、テストは落ちるだろうか?」
これはミューテーションテストという考え方の、手でできる簡易版です。 ミューテーションテストとは、コードをわざと少し書き換えて(+ を - にする、条件を反転する等)、その「壊れたコード」をテストが検出できるかを測る手法。テストの本当の強さは、正しいコードで通ることではなく、間違ったコードで落ちることで分かります。
専用ツール(例:Stryker、PIT など)を使えば自動でできますが、まずは頭の中で、あるいは手で試すだけでも十分です。
- 戻り値の計算式を、わざと少し変えてみる → テストは落ちる?
ifの条件を反転してみる → テストは落ちる?- 境界の
<=を<に変えてみる → テストは落ちる?
落ちなければ、そのテストはその部分を守れていません。 カバレッジ上は緑でも、そこは実質ノーガードです。逆に、ちゃんと落ちるなら、そのテストは「壊れたら気づける」意味のあるテスト。この一問を通すだけで、数字の裏側がかなり見えてきます。
数字を「見せかけ」から「安全網」に変える確認の順番
AIが上げたカバレッジを、頭ごなしに疑う必要はありません。 数字はスタート地点として使い、中身を人が確かめる——この順番で見ると、効率よく品質を上げられます。
- カバレッジで「手つかずの場所」を見つける:カバレッジが低い所は、そもそもテストが無い所。ここは分かりやすいので、まず埋める候補にします。数字はこの用途には有効です。
- カバレッジが高い所こそ中身を見る:緑になっている所に、「呼ぶだけ」「実装なぞり」「ハッピーパスだけ」が隠れています。高い所を疑うのがコツ。
- 重要な関数を1〜2個選び、ミューテーションを手で試す:全部は無理でも、お金・データ・認証など壊れたら痛い所だけ、わざと壊してテストが落ちるか確かめます。
- 抜けている観点を洗い出す:境界・異常系・仕様の意図。ここはAIにも手伝わせつつ、最後は人が「この仕様、テストで表現できているか」を見ます。
ポイントは、カバレッジを「これ以上テストが要らない証明」に使わないこと。 カバレッジは「どこがまだ手つかずか」を教えてくれる地図であって、「もう安全だ」という保証書ではありません。地図として使えば、とても役に立ちます。
任せる/見るの早見表
迷ったときのために、一覧にしておきます。あくまで目安なので、現場の事情に合わせて調整してください。
| 観点 | AIに任せやすい | 人が必ず見る | ひとことで |
|---|---|---|---|
| テストの雛形・件数を増やす | ◎ | △ | 量産はAIが速い |
| 正常系(ハッピーパス)の網羅 | ◎ | ○ | AIの得意分野 |
| アサーションが意味を持つか | △ | ◎ | 何を確かめるかは人 |
| 境界・異常系の洗い出し | ○ | ◎ | 案出しはAI、要否は人 |
| 期待値が仕様から来ているか | × | ◎ | 実装なぞりを人が排除 |
| 壊れたら落ちるか(ミューテーション) | △ | ◎ | 最後の砦は人 |
| このカバレッジで出荷していいか | × | ◎ | 判断は必ず人 |
◎=任せやすい/○=人が確認しつつ活用/△=参考程度/×=任せない、の目安です。 上半分(量・雛形・正常系)はAIに寄せ、下半分(検証の意味・仕様との一致・出荷判断)に人の時間を残す。これが「数字に振り回されない」テストの設計です。
AIに「意味のあるテスト」を書かせるプロンプトの型
「テストを書いて」とだけ頼むと、AIはカバレッジを上げやすい正常系を量産しがちです。 何を検証してほしいか・どこを重点的に見るか・期待値の決め方を渡すと、中身のあるテストに近づきます。
渡すと良いもの:
- その関数の仕様・意図(何を保証したいのか。「価格を計算する」ではなく「税込みで、端数は切り捨て」まで)
- 期待値は仕様から決めてほしいという指示(実装をなぞらせない)
- 重点的にカバーしてほしい観点(境界・異常系・エラー時の振る舞い)
- アサーションを具体的にという指示(
toBeDefinedだけで終わらせない)
聞き方の例:
次の関数のテストを書いてください。カバレッジの数字より、「壊れたら落ちる」テストを重視します。
## 関数の仕様(意図)
(何を保証したいか。境界や端数の扱い、エラー時の振る舞いまで具体的に)
## お願いしたいこと
- 期待値は「仕様」から決めてください。実装のコードをそのまま計算式にしないでください。
- 具体的な期待値(例:110、空配列、特定のエラー)でアサーションしてください。
toBeDefined など「存在するだけ」の検証で終わらせないでください。
- 次の観点を必ず含めてください:
- 正常系(代表的な入力)
- 境界(0・上限・下限・空・最大長など)
- 異常系(null/不正な型/範囲外/エラーが起きるべきケース)
- 各テストに「何を確かめているか」を1行コメントで添えてください。
## 補足
自信のないケースや、仕様が曖昧で判断できない所は「要確認」と明記してください。
ポイントは2つ。 1つは「期待値は仕様から決めて」と明示すること。これで「実装なぞり」テストをかなり防げます。 もう1つは「存在するだけの検証で終わらせない」と釘を刺すこと。AIは放っておくとゆるいアサーションに流れやすいので、具体的な値を求めます。それでも生成された単体テストは、生成された単体テストを信用しすぎないための確認ポイントの通り、人が一度は目を通す前提で使います。
AIのテストを受け取ったあとの、10分でできる点検
生成されたテストが返ってきたら、全部を精読しなくても、要点だけ10分で点検できます。
- アサーションの中身を見る:
expect(...)が具体的な値を確かめているか。toBeDefined/not.toThrowだけのものは要注意。 - 期待値の出どころを疑う:期待値が実装と同じ式になっていないか。仕様から来た具体値か。
- 端っこがあるか数える:境界・異常系のテストがいくつあるか。正常系ばかりなら偏っています。
- 1個だけ壊してみる:いちばん大事な関数の計算や条件を1か所だけ変えて、テストが赤くなるか。落ちなければ、そこは守れていません。
- テスト名と中身が合っているか:「マイナス入力を弾く」という名前なのに、実際はマイナスを渡していない、という不一致がないか。
この5つは、カバレッジのレポートには一切出てこない情報です。 でも、この10分が「90%だけど不安」を「90%で、中身も見た」に変えてくれます。数字と中身の両輪がそろって、はじめて安心して出荷できます。
ありがちな落とし穴と、その回避
- カバレッジ100%を目標にしてしまう:100%を目指すと、意味の薄いテストを量産して数字を埋めがち。数字は地図であって目的ではない。重要な所の質を優先する。
- 緑のバーを見て安心する:緑は「通った」だけ。「確かめた」ではない。高い所ほど中身を疑う。
- AIの期待値をそのまま信じる:AIは実装をなぞった期待値を書くことがある。仕様から見て正しいか、人が確かめる。
- 正常系の数で満足する:テストの本数が多くても、端っこが抜けていればバグは残る。件数より観点の偏りを見る。
- 一度書いたら見直さない:仕様が変われば、意味のあるテストも変わる。カバレッジが高いままでも、守っている中身が古びていないか。
- カバレッジを人の点検の言い訳にする:「90%あるから見なくていい」ではなく、「90%の中身を見る余力を、数字が作ってくれた」と捉える。
落とし穴のほとんどは、カバレッジという「量の数字」を、「質の証明」として読んでしまうところから生まれます。 量と質は別の物差し。分けて見るだけで、多くは避けられます。
明日からやること(小さく始める3つ)
いきなり仕組みを整えようとせず、まずこの3つから。
- いちばん大事な関数のテストを1つ開いて、実装を1か所わざと壊す:テストが落ちれば合格。落ちなければ、そこはノーガードだったと分かります。
- AIへの依頼に「期待値は仕様から決めて/具体的な値で検証して」を1行足す:これだけで「呼ぶだけ」テストがぐっと減ります。
- カバレッジが高い所を1か所選んで、アサーションの中身を読む:低い所ではなく、あえて緑の所を疑うのがコツです。
この3つだけでも、「数字はいいのに不安」が、「数字の意味を自分で確かめた」に変わっていきます。
コピーして使う「テストの質チェック」
AIのテストを受け取ったとき、上から順に確認してください。一度に全部でなく、大事な関数だけで十分です。
# AIテスト 質チェック
## ① アサーション(何を確かめているか)
- 具体的な値を検証しているか(toBeDefined/not.toThrow だけで終わっていないか):
- テスト名と、実際に確かめている中身は一致しているか:
## ② 期待値の出どころ
- 期待値は「仕様」から決めているか(実装のコードをなぞっていないか):
## ③ 観点の偏り
- 正常系だけに偏っていないか:
- 境界(0・上限・下限・空・最大長)のテストはあるか:
- 異常系(null・不正な型・範囲外・エラー時)のテストはあるか:
## ④ 壊して確かめる(ミューテーションの発想)
- 重要な関数の計算/条件を1か所壊したら、テストは落ちるか:
- 落ちなかった箇所はどこか(=実質ノーガード):
## ⑤ 出荷判断(人が決める)
- カバレッジの数字ではなく、中身を見て「出していい」と言えるか:
テスト前後のチェックリスト
任せる前と、出荷を判断する前に、さっと確認します。全部に○が要るわけではなく、関係する所だけで十分です。
AIにテストを頼む前
- 関数の仕様・意図(境界や端数、エラー時まで)を渡したか
- 「期待値は仕様から」「具体的な値で検証」を頼んだか
- 境界・異常系を含めるよう観点を渡したか
テストを受け取ったとき
- アサーションが具体的な値を確かめているか見たか
- 期待値が実装なぞりになっていないか確かめたか
- 正常系に偏っていないか、端っこがあるか数えたか
出荷を判断する前
- 重要な関数を1か所壊して、テストが落ちることを確かめたか
- カバレッジの数字ではなく、中身を見て判断したか
- 「90%だから安全」ではなく「中身も見た」と言えるか
最後に
カバレッジの数字がきれいに並んでいるのに、なぜか安心できない。 その夜の違和感を、「気にしすぎかな」と流さずにここまで読んだあなたは、もう数字の裏側を見ようとしています。それは、テストと誠実に向き合っている人の感覚です。

全部のテストを完璧にしなくて大丈夫です。今日ひとつ、大事な関数のテストを開いて、実装をわざと壊してみる。それだけで、カバレッジの数字が「見せかけ」から「自分で確かめた安全網」に変わります。 生成された単体テストの確認は生成された単体テストを信用しすぎないための確認ポイント、観点の洗い出しはAIにテストケースを洗い出させるときの観点の与え方に整理しています。数字は味方にしつつ、中身は自分の目で。その両輪があれば、AIのテストは頼れる安全網になります。