PITestを使用したミューテーションテスト

1。概要

ソフトウェアテストとは、ソフトウェアアプリケーションの機能を評価するために使用される手法を指します。この記事では、コードカバレッジミューテーションテストなど、ソフトウェアテスト業界で使用されるいくつかのメトリックについて、PITestライブラリを使用してミューテーションテストを実行する方法に特に関心を持って説明します。

簡単にするために、このデモンストレーションは基本的な回文関数に基づいています。回文は、同じように前後に読み取る文字列であることに注意してください。

2.Mavenの依存関係

Mavenの依存関係の構成でわかるように、JUnitを使用してテストを実行し、PITestライブラリを使用してコードにミュータントを導入します。心配しないでください。ミュータントが何であるかがすぐにわかります。このリンクをたどると、Maven中央リポジトリに対する最新の依存関係バージョンをいつでも検索できます。

 org.pitest pitest-parent 1.1.10 pom  

PITestライブラリを稼働させるには、pom.xml構成ファイルにpitest-mavenプラグインを含める必要もあります。

 org.pitest pitest-maven 1.1.10   com.baeldung.testing.mutation.*   com.baeldung.mutation.test.*    

3.プロジェクトのセットアップ

Mavenの依存関係が構成されたので、この自明の回文関数を見てみましょう。

public boolean isPalindrome(String inputString) { if (inputString.length() == 0) { return true; } else { char firstChar = inputString.charAt(0); char lastChar = inputString.charAt(inputString.length() - 1); String mid = inputString.substring(1, inputString.length() - 1); return (firstChar == lastChar) && isPalindrome(mid); } } 

ここで必要なのは、実装が目的の方法で機能することを確認するための単純なJUnitテストです。

@Test public void whenPalindrom_thenAccept() { Palindrome palindromeTester = new Palindrome(); assertTrue(palindromeTester.isPalindrome("noon")); } 

これまでのところ、JUnitテストとしてテストケースを正常に実行する準備ができています。

次に、この記事では、PITestライブラリを使用したコードとミューテーションのカバレッジに焦点を当てます。

4.コードカバレッジ

コードカバレッジは、自動テスト中に実行パスの何パーセントが実行されたかを測定するために、ソフトウェア業界で広く使用されています。

Eclipse IDEで利用可能なEclemmaなどのツールを使用して、実行パスに基づいて効果的なコードカバレッジを測定できます。

コードカバレッジでTestPalindromeを実行した後、100%のカバレッジスコアを簡単に達成できます– isPalindromeは再帰的であるため、空の入力長チェックがとにかくカバーされることは明らかです。

残念ながら、コードカバレッジメトリックは、100%のコードカバレッジスコアはすべての行が少なくとも1回実行されたことを意味するだけであるため、まったく効果がない場合がありますが、テストの精度ユースケースの完全については何も述べていません。そのため、ミューテーションテストが実際に重要です。

5.ミューテーションカバレッジ

ミューテーションテストは、テストの妥当性改善し、コードの欠陥特定するために使用されるテスト手法です。アイデアは、本番コードを動的に変更し、テストを失敗させることです。

良いテストは失敗する

コードが変更されるたびにミュータントと呼ばれ、ミューテーションと呼ばれるプログラムのバージョンが変更されます。

それがテストで失敗を引き起こす可能性がある場合、突然変異は殺されると言います。また、突然変異体がテストの動作に影響を与えることができなければ、突然変異は生き残ったとも言います。

次に、ゴールオプションをorg.pitest:pitest-maven:mutationCoverageに設定して、Mavenを使用してテストを実行しましょう。

target / pit-test / YYYYMMDDHHMIディレクトリでHTML形式のレポートを確認できます。

  • 100%の回線カバレッジ:7/7
  • 63%の突然変異カバレッジ:5/8

明らかに、テストはすべての実行パスをスイープするため、ラインカバレッジスコアは100%です。一方、PITestライブラリは8つのミュータントを導入し、そのうち5つが殺され、失敗を引き起こしましたが、3つは生き残りました。

作成されたミュータントの詳細については、com.baeldung.testing.mutation /Palindrome.java.htmlレポートを確認できます。



これらは、ミューテーションカバレッジテストを実行するときにデフォルトでアクティブになるミューテーターです

  • INCREMENTS_MUTATOR
  • VOID_METHOD_CALL_MUTATOR
  • RETURN_VALS_MUTATOR
  • MATH_MUTATOR
  • NEGATE_CONDITIONALS_MUTATOR
  • INVERT_NEGS_MUTATOR
  • CONDITIONALS_BOUNDARY_MUTATOR

PITestミューテーターの詳細については、公式ドキュメントページのリンクを確認してください

回文関数が非パリンドロームおよびニアパリンドロームの文字列入力を拒否することを確認できないため、ミューテーションカバレッジスコアはテストケースの欠如を反映しいます。

6.突然変異スコアを改善する

Now that we know what a mutation is, we need to improve our mutation score by killing the surviving mutants.

Let's take the first mutation – negated conditional – on line 6 as an example. The mutant survived because even if we change the code snippet:

if (inputString.length() == 0) { return true; }

To:

if (inputString.length() != 0) { return true; }

The test will pass, and that's why the mutation survived. The idea is to implement a new test that will fail, in case the mutant is introduced. The same can be done for the remaining mutants.

@Test public void whenNotPalindrom_thanReject() { Palindrome palindromeTester = new Palindrome(); assertFalse(palindromeTester.isPalindrome("box")); } @Test public void whenNearPalindrom_thanReject() { Palindrome palindromeTester = new Palindrome(); assertFalse(palindromeTester.isPalindrome("neon")); }

Now we can run our tests using the mutation coverage plugin, to make sure that all the mutations were killed, as we can see in the PITest report generated in the target directory.

  • 100% line coverage: 7/7
  • 100% mutation coverage: 8/8

7. PITest Tests Configuration

Mutation testing may be resources-extensive sometimes, so we need to put proper configuration in place to improve tests effectiveness. We can make use of the targetClasses tag, to define the list of classes to be mutated. Mutation testing cannot be applied to all classes in a real world project, as it will be time-consuming, and resource critical.

It is also important to define the mutators you plan to use during mutation testing, in order to minimize the computing resources needed to perform the tests:

  com.baeldung.testing.mutation.*   com.baeldung.mutation.test.*   CONSTRUCTOR_CALLS VOID_METHOD_CALLS RETURN_VALS NON_VOID_METHOD_CALLS  

Moreover, the PITest library offers a variety of options available to customize your testing strategies, you can specify the maximum number of mutants introduced by class using the maxMutationsPerClass option for example. More details about PITest options in the official Maven quickstart guide.

8. Conclusion

Note that code coverage is still an important metric, but sometimes it is not sufficient enough to guarantee a well-tested code. So in this article we've walked through mutation testing as a more sophisticated way to ensure tests quality and endorse test cases, using the PITest library.

また、ミューテーションカバレッジスコアを改善しながら、基本的なPITestレポートを分析する方法も確認しました。

ミューテーションテストでコードの欠陥が明らかになったとしても、非常にコストと時間がかかるプロセスであるため、賢明に使用する必要があります

リンクされたGitHubプロジェクトで、この記事で提供されている例を確認できます。