Skip to content
Latchkey

ミューテーションテストとは?

ミューテーションテストは、意図的に小さなバグを注入し、テストがそれを検出するかを確認することで、テストの品質を測定します。

カバレッジはテスト中にどのコードが実行されたかを教えてくれますが、テストがバグに気づくかどうかは教えてくれません。ミューテーションテストはその難しい問いに答えます。コードをミューテート(演算子を反転させたり定数を変更したり)し、スイートを再実行します。テストが失敗すればそのミュータントは「殺され」、すべてのテストが依然としてパスすればミュータントは「生き残り」、弱点を露呈します。

ミュータントの作り方

ミューテーションツールは、それぞれ1つの小さな変更を加えたコードのわずかに変更されたバージョンを多数生成します。プラスがマイナスになり、より小さいがより小さいか等しいになり、戻り値が削除されるといった具合です。各ミュータントは、開発者が導入しうる現実的なバグを表します。

殺されたか生き残ったか

各ミュータントについてスイートが再実行されます。少なくとも1つのテストが失敗すれば、テストがバグを検出したことになり、そのミュータントは殺されます。すべてのテストが依然としてパスすれば、ミュータントは生き残り、テストがそのバグを検出できなかったことを意味します。生き残ったものは、弱いまたは欠けているアサーションを正確に指し示します。

ミューテーションスコア

ミューテーションスコアとは、殺されたミュータントの割合です。カバレッジと異なり、これは単なる実行ではなくアサーションの品質を反映します。高いミューテーションスコアは、テストが実際に振る舞いを検証していることの強力な証拠であり、だからこそより厳しい指標なのです。

簡単な例

ツールが > を >= に変更しても、どのテストも失敗しない場合、境界ケースはテストされておらず、修正する価値のある生き残りです。

A boundary mutation
if (age > 18) { ... }   // original
if (age >= 18) { ... }  // mutant: did any test catch it?

ミューテーションテストとCIコスト

ミューテーションテストは高コストです。ミュータントごとに1回スイートを再実行するため、通常のテスト実行より桁違いに遅くなることがあります。チームはプッシュごとではなく夜間やスケジュールで実行し、大幅に並列化することがよくあります。ミュータントを高速なrunnerに分散させることが、実現可能に保つ鍵です。

重要なポイント

  • ミューテーションテストは、注入されたバグをテストが検出するかを見て採点します。
  • 生き残ったミュータントは、弱いまたは欠けているアサーションを明らかにします。
  • コストが高いため、スケジュールで実行し、runner間で並列化しましょう。

関連ガイド