
皆さんの多くは、素晴らしいPodcast
DebriefingポッドキャストでMutation Testingについて聞いたことがあるか、
Wikipediaで読んだことがあります。 まだ概念に慣れていない人のために、簡単に説明します。
突然変異テストは、
テストの品質を測定するための代替アプローチです。 一般的なコードカバレッジをカウントする代わりに、より合理的なメカニズムが使用されます。 ランダムクラス(別名、
ミューテーション)は、クラスのバイトコードに導入されます。 そのような突然変異の後に行われた変更をカバーする単一のテストが落ちなかった場合、テストであまりうまくやっていない可能性があります。 可能な突然変異の例:
それは: |
if(somevalue < threshold) { doSomething(); }
|
次のようになりました: |
if(somevalue >= threshold) { doSomething(); } |
このコードブロックをカバーするテストは必ず実行される必要があるため、変更は非常に重要です。 カットの下で、非常に優れた
Pitestライブラリについて説明し、それをプロジェクトに接続する方法を示し、テスト結果を実際のコードで提供します。
シンプルなプロジェクト
単一のクラスを含む単純な
[ github ]プロジェクトから始めましょう。
1 2 3 4 5 6 8 | public class ClassToTest { private static final double THRESHOLD = 10.0; public static boolean threshold(double value) { return value >= THRESHOLD; } } |
そしてそれをテストします:
1 2 3 4 5 | @Test public void testThreshold() { Assert.assertTrue(ClassToTest.threshold(10.0)); Assert.assertFalse(ClassToTest.threshold(9.0)); } |
pitestを接続するには、プラグインをmavenに追加するだけです:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <plugin> <groupId>org.pitest</groupId> <artifactId>pitest-maven</artifactId> <version>0.25</version> <configuration> <inScopeClasses> <param>com.example*</param> </inScopeClasses> <targetClasses> <param>com.example*</param> </targetClasses> </configuration> </plugin> |
構成についてもう少し詳しく説明します
inScopeClasses
は、変更する必要があるテストとクラスを探すためのクラスを定義します。
targetClasses
は、変更するだけのクラスを定義します。 さらに、いくつかのオプションがあり、その完全なリストは
こちらにあります 。
何らかの理由でmavenを使用していない場合、すべてがなくなっているわけではありません。コマンドラインから使用でき
ます 。マニュアルは
こちらから入手でき
ます 。
そして、mavenを使用して幸せを見つけるには、次のコマンドを実行します。
mvn org.pitest:pitest-maven:mutationCoverage |
レポートについて
チェックの結果、ログのシートがかなり大きくなります。 読むのは特に便利ではありませんが、
target/pit-reports/%TIMESTAMP%
フォルダーでは、コードカバレッジに類似したhtmlレポートも生成されます。 私たちの場合、その興味深い部分は次のようになります。

ここの行14に近い3番目の数字は、この行に適用された突然変異の数を意味します。 以下の突然変異セクションでは、各ラインについて、どの突然変異が適用され、結果がどうであったかを説明しています。
突然変異の結果
- KILLED-突然変異の結果、この文字列をチェックするすべてのテストが失敗しました。 わが国では、すべての突然変異がそのようなステータスを持っていることに気付くかもしれません。
- SURVIVED-突然変異は見過ごされました。 つまり、機能の変更はテストの対象外です。
- TIMED_OUT-テストが長すぎる(たとえば、無限ループの結果として)
- NON_VIABLE-何らかの理由で、突然変異の結果のバットコードが無効であることが判明しました(めったに起こりません)
- MEMORY_ERROR-突然変異の結果、コードが大量のメモリを消費し始め、OOMから落ちました
- RUN_ERROR-突然変異の結果として、例外をスローするコードが生成されます
突然変異の種類
現時点では、11の突然変異しかない。 緑色で強調表示されているのは、デフォルトで有効になっているものです。
- CONDITIONALS_BOUNDARY-チェックで厳密な不等式を非厳密に変更し、逆も同様です。 たとえば、
<
は<=
- NEGATE_CONDITIONALS-条件を反転します。 たとえば、
==
は!=
- MATH-使用されている数学演算子を置き換えます 。 たとえば、マイナスからプラスに変わります。
- インクリメント-インクリメントをデクリメントに、またはその逆に置き換えます
- INVERT_NEGS-整数と実数の符号を反転します
- INLINE_CONSTS-リテラルを変更し、代わりに別の値を置き換えます。 たとえば、
42
は42
に置き換えられ、 true
はfalse
に置き換えられtrue
- RETURN_VALS-メソッドによって返された値を他の値に置き換えます 。 たとえば、本格的なオブジェクトの代わりに、nullが返されます。
- VOID_METHOD_CALLS -voidメソッド呼び出しを削除します
- NON_VOID_METHOD_CALLS-非voidメソッドを呼び出す代わりに、このメソッドのタイプのデフォルト値(
false
、 0
、 null
)を返します - CONSTRUCTOR_CALLS-コンストラクターを呼び出す代わりにnullを使用します
- EXPERIMENTAL_INLINE_CONSTS - INLINE_CONSTSに似ていますが、ややスマートです
さまざまなタイプの突然変異の詳細な説明は
、公式ウェブサイトで入手できます。
例の複雑化
サンプルプロジェクトでは、突然変異は条件(2個)と戻り値にありました。 ここで、より多くの突然変異を達成してみましょう。 クラス自体を次のように書き換えます。
1 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class ClassToTest { private int invocationCount = 0; private static final double OFFSET = 1.0; private final double threshold; public ClassToTest(double threshold) { this.threshold = threshold; } public boolean threshold(double value) { logInvocation(); return value >= threshold + OFFSET; } private void logInvocation() { invocationCount++; } } |
しかし、テストでは、新しい機能をテストしません。
1 2 3 4 5 6 7 | @Test public void testThreshold() { ClassToTest classToTest = new ClassToTest(10.0); Assert.assertTrue(classToTest.threshold(11.0)); Assert.assertFalse(classToTest.threshold(10.0)); } |
コードカバレッジを実行する場合、問題は検出されません。 しかし、突然変異テストを実行すると、彼らはすぐに手で私たちをつかんで言います:しかし、機能はテストされていません!

成功! これで、実際にテストされるコードとテストされないコードをかなり正確に言うことができ、実際には何もチェックしないあらゆる種類の「推定」テストが迅速に検出されます。
なぜまさにピストですか?
一般的に言えば、突然変異テストの考え方は新しいものではなく、いくつかのライブラリがすでに存在しています。 これらの中で最も注目すべきは
Javalancheと
Jumbleです。 ただし、これらのライブラリやその他のライブラリは特に積極的に開発されているわけではありません。一部のライブラリは低速でバグが多く、ビルドシステムやその他のライブラリとは実質的に統合されていません。 詳細な比較は
こちらから入手でき
ます 。
実際のプロジェクトを確認する
興味を引くために、実際のプロジェクトで、コードカバレッジでは検出できない問題を突然変異テストで検出する方法を示すのが正しいでしょう。 これには、コードカバレッジを読み取るユーティリティであるCoberturaが最適です。 彼女のレポートは
ここで完全に見つけることができます、そして私はほんの少しだけを与えます。 それを得るには、ソースにmavenのサポートを追加して少し汗をかき、
約20分間待機する必要がありました。その間、突然変異のテストが続きます。 。 結果は次のとおりです。
Coberturaは、すべてが正常であることを示しています。 |
 |
Pitestはカバーを引き裂きます。 |
 |
合計
全体として、このアプローチはクールであり、コードカバレッジよりもはるかに正確にテストの品質を明確に評価します。 もちろん、このようなチェックは通常のカバレッジよりもはるかに長く機能するため、大規模なプロジェクトでは数時間かかる場合があります。 さらに、Pitestライブラリ自体はまだ多少湿っています。 たとえば、複数のスレッドでテストを実行したり、すべてのテストを変更せずに正常に完了したりすることはできません。 しかし、このプロジェクトは
オープンソースであり、非常に活発に開発されているため、しばらくしてから真剣に使用することについて考え始めることができると信じています。
質問、コメント、コメントの修正を待っています!