AI が書いたテストの「効き目」をミューテーションテストで測る(@mizchi/mutator)
AI はテストを大量に書けるが、通るだけで何も守っていないテストも混ざる。コードをわざと少し壊し(ミュータント)、テストが落ちるかを見て、検出できなかった箇所を AI に直させる。
どんな時に使う?
- エージェントにテストを書かせたが、カバレッジが高いのにバグを見逃している気がする
>=と>のような境界条件を本当に検査しているか知りたい- PR ごとに「テストが弱くなっていないか」を CI で止めたい
手順
bash
pnpm add -D @mizchi/mutator
pnpm exec mutator # 全体を一度走らせる
pnpm exec mutator --since main # main からの差分だけ(HEAD も指定可)
pnpm exec mutator --scope <scope> # 範囲を絞る
pnpm exec mutator --only <対象> # 特定の対象だけ
pnpm exec mutator --since origin/main --fail-on-survived # 生き残りがあれば exit 2(CI 用)
pnpm exec mutator --reporter agent # text / html / json / agent
pnpm exec mutator accept # 等価ミュータント(壊しても意味が同じ)を承認して除外- 結果は「到達しない(not reached)」「壊れても値が変わらない(not infected)」「値は変わったがテストが落ちない(not detected)」に分かれる。直すべきは主に not detected
- 結果は
.mutator/snapshot.jsonと.mutator/report/に残る。2回目以降は差分だけを回すので速い(作者のベンチでは StrykerJS 10 と比べ、差分実行は約1秒) - 例:
isAdultのage >= 18を> 18に変えても落ちなければ、18歳ちょうどのテストが無い
エージェントとの回し方
- 実装とテストをエージェントに書かせる
mutator --since main --reporter agentの出力をそのまま渡し「生き残ったミュータントを殺すテストを足して。実装は変えない」と頼む- 等価ミュータントだと判断したものだけ人が見て
mutator accept - CI には
--fail-on-survivedを入れる
注意点
- 全体実行は重い。普段は
--sinceで差分だけにする - 「実装を変えて生き残りを消す」方向に逃げないよう、テストだけを足すと明示する
- テストの層の分け方は E2E に全部載せない:AI にテストを書かせる前に層を4つの基準で振り分ける、実装から仕様を検査する方向は 「バイブ形式手法」: 実装から仕様を吸い出し、Z3/TLA+ で反例を探して CI に載せる
出典
- @mizchi · 2026-10-27
- 解説記事(Zenn): zenn.dev