ミューテーションテスト
テストコードの品質を、意図的にコードを変異させて検証する手法
テスト品質
ミューテーションテストとは
ミューテーションテスト (Mutation Testing) は、ソースコードに意図的な変異 (ミュータント) を加え、既存のテストがその変異を検出できるかを検証する手法である。テストの品質を測る「テストのテスト」と言える。
コードカバレッジが 100% でも、テストが実際にバグを検出できるとは限らない。ミューテーションテストは、テストの検出力 (バグを見つける能力) を定量的に評価する。
仕組み
元のコードに小さな変異 (ミュータント) を加え、既存のテストスイートがその変異を検出できるかを確認する。テストが失敗すればミュータントは「殺された」(テストが有効)、テストが通過すればミュータントは「生存」(テストが不足) と判定される。
1. 元のコード: if (age >= 18) return "adult";
2. ミュータント生成: if (age > 18) return "adult"; (>= を > に変異)
3. テスト実行: age=18 のテストケースがあれば失敗 → ミュータント「殺された」(検出成功)
age=18 のテストがなければ通過 → ミュータント「生存」(テスト不足)
ミューテーションスコア
ミューテーションスコアを図で示す。
ミューテーションスコア = 殺されたミュータント数 / 全ミュータント数 × 100%
| スコア | 評価 |
|---|---|
| 90% 以上 | テストの検出力が高い |
| 70〜90% | 改善の余地あり |
| 70% 未満 | テストが不十分 |
代表的な変異演算子
代表的な変異演算子を以下にまとめる。
| 演算子 | 元のコード | 変異後 |
|---|---|---|
| 条件境界 | >= |
> |
| 否定 | if (x) |
if (!x) |
| 算術演算子 | a + b |
a - b |
| 戻り値 | return true |
return false |
| 削除 | validate(input) |
(行を削除) |
コードカバレッジとの違い
コードカバレッジとの違いを以下にまとめる。
| 指標 | コードカバレッジ | ミューテーションスコア |
|---|---|---|
| 測定対象 | コードの実行率 | テストの検出力 |
| 弱点 | 実行しただけで検証していないコードも 100% | 計算コストが高い |
| 例 | add(1, 2) を呼ぶだけで行カバレッジ 100% |
add の結果を assertEquals で検証しないとミュータント生存 |
ツール
主なツールを以下にまとめる。
| 言語 | ツール |
|---|---|
| JavaScript/TypeScript | Stryker |
| Java | PIT (pitest) |
| Python | mutmut |
| Rust | cargo-mutants |
実務での活用
全コードにミューテーションテストを適用すると実行時間が膨大になるため、以下のように対象を絞る。
- ビジネスロジックの核心部分 (金額計算、権限チェック) に限定する
- 新規コードの PR レビュー時に CI で実行する
- コードカバレッジが高いのにバグが出る領域に適用する
関連書籍も参考になる。
この記事は役に立ちましたか?
関連用語
関連する記事
テスト本ガイド - テスト設計を学べる技術書の選び方
テストの書き方からテスト戦略まで学べる技術書の選び方を紹介。テストピラミッド、TDD の正しい読み方、テストの ROI の考え方を解説します。
バグを生むのは知識不足ではなく想像力不足である
バグの多くは、コードを書いた時点で「こういうケースもありうる」と想像できなかったことが原因です。想像力を鍛える読書法と、エッジケースへの感度を高める方法を解説します。
「動くコード」と「良いコード」の間にある本
コードが動くようになった後、次に何を学べばよいのか。「動くコード」を「良いコード」に変えるために必要な知識と、それを効率的に学べる本の選び方を解説します。