Maven - PITest突然変異のテストの例

image

この記事では、http://pitest.org/quickstart/maven/[Maven PIT突然変異検査プラグイン]を使用して、Javaプロジェクトの突然変異検査カバレッジレポートを生成する方法を説明します。

テスト済み

  1. Maven 3.5.3

  2. JUnit 5.3.1

  3. PITest 1.4.3

1. Quick-Maven PITest Plugin

1.1 PIT突然変異検査を有効にするには、この pitest-maven`を pom.xml`に入れます。

pom.xml

    <plugin>
        <groupId>org.pitest</groupId>
        <artifactId>pitest-maven</artifactId>
        <version>1.4.3</version>

        <executions>
            <execution>
                <id>pit-report</id>
                <!-- optional, this example attached the goal into mvn test phase -->
                <phase>test</phase>
                <goals>
                    <goal>mutationCoverage</goal>
                </goals>
            </execution>
        </executions>

        <!-- https://github.com/hcoles/pitest/issues/284 -->
        <!-- Need this to support JUnit 5 -->
        <dependencies>
            <dependency>
                <groupId>org.pitest</groupId>
                <artifactId>pitest-junit5-plugin</artifactId>
                <version>0.8</version>
            </dependency>
        </dependencies>
        <configuration>
            <targetClasses>
                <param>com.mkyong.examples.** </param>
            </targetClasses>
            <targetTests>
                <param>com.mkyong.examples.** </param>
            </targetTests>
        </configuration>
    </plugin>

1.2 PITestを手動で実行します。

$ mvn clean org.pitest:pitest-maven:mutationCoverage

1.3 `pom.xml`ファイルの上にMavenテストフェーズに 'mutationCoverage’ゴールが添付されました。今、Mavenテストを実行すると、自動的にPITestテストがトリガーされます。

$ mvn clean test

1.4レポートは `target/pit-reports/YYYYMMDDHHMI/** `で生成されます

2.突然変異検査とは何ですか?

2.1突然変異試験は、試験の有効性を測定するために使用される。

突然変異テストでは、コードをさまざまな突然変異に変更/変更するために、http://pitest.org/quickstart/mutators[mutators](数学演算子の切り替え、戻り値のタイプの変更、呼び出しの削除など)を使用します突然変異が起こった場合にユニットテストが失敗するかどうかを確認してください。

検査の有効性は、どのように多くの突然変異が死亡するかの尺度となり得る。

2.2たとえば、次のコード:

    public boolean isPositive(int number) {

        boolean result = false;
        if (number >= 0) {
            result = true;
        }
        return result;

    }

デフォルトでは、PITestは異なるhttp://pitest.org/quickstart/mutators/[mutators]を使用して上記のコードを異なる突然変異(新しいコード)に変換します:

#1変異 - 変更された条件境界(ミューテータ)

    public boolean isPositive(int number) {

        boolean result = false;
       //mutator - changed conditional boundary
        if (number > 0) {
            result = true;
        }
        return result;

    }

#2突然変異 - 条件付き否定(ミューテータ)

    public boolean isPositive(int number) {

        boolean result = false;
       //mutator - negated conditional
        if (false) {
            result = true;
        }
        return result;

    }

#3突然変異 - 整数サイズの値の(x == 0?1:

0)(ミューテータ)

    public boolean isPositive(int number) {

        boolean result = false;
        if (number > 0) {
            result = true;
        }

       //mutator - (x == 0 ? 1 : 0)
        return !result;

    }

2.3良い単位テストはすべての突然変異#1、#2、#3を失敗(殺す)すべきである。

    @Test
    public void testPositive() {

        CalculatorService obj = new CalculatorService();
        assertEquals(true, obj.isPositive(10));

    }

上記の単体テストは突然変異#2と#3を殺す(単体テストは失敗する)が、突然変異#1は生存する(単体テストが渡される)。

image

2.4突然変異#1をもう一度見直す。このテスト(突然変異)を失敗(強制終了)するには、条件付き境界である数値ゼロをテストする必要があります。

    public boolean isPositive(int number) {

        boolean result = false;
       //mutator - changed conditional boundary
        if (number > 0) {
            result = true;
        }
        return result;

    }

数字のゼロをテストしてユニットテストを改善する。

    @Test
    public void testPositive() {

        CalculatorService obj = new CalculatorService();
        assertEquals(true, obj.isPositive(10));
       //kill mutation #1
        assertEquals(true, obj.isPositive(0));

    }

完了、100%突然変異カバレッジ。

image

3. MavenのPITestの例

別の完全なMaven PITestの例。自己参照用です。

3.1完全な pom.xml

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mkyong.examples</groupId>
    <artifactId>maven-mutation-testing</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <!-- https://maven.apache.org/general.html#encoding-warning -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>5.3.1</junit.version>
        <pitest.version>1.4.3</pitest.version>
    </properties>

    <dependencies>

        <!-- junit 5, unit test -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
    <build>
        <finalName>maven-mutation-testing</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M1</version>
            </plugin>

            <plugin>
                <groupId>org.pitest</groupId>
                <artifactId>pitest-maven</artifactId>
                <version>${pitest.version}</version>

                <executions>
                    <execution>
                        <id>pit-report</id>
                        <phase>test</phase>
                        <goals>
                            <goal>mutationCoverage</goal>
                        </goals>
                    </execution>
                </executions>

                <!-- https://github.com/hcoles/pitest/issues/284 -->
                <!-- Need this to support JUnit 5 -->
                <dependencies>
                    <dependency>
                        <groupId>org.pitest</groupId>
                        <artifactId>pitest-junit5-plugin</artifactId>
                        <version>0.8</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <targetClasses>
                        <param>com.mkyong.examples.** </param>
                    </targetClasses>
                    <targetTests>
                        <param>com.mkyong.examples.** </param>
                    </targetTests>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

3.2ソースコード

StockService.java

package com.mkyong.examples;

public class StockService {

    private int qtyOnHand;

    public StockService(int qtyOnHand) {
        this.qtyOnHand = qtyOnHand;
    }

    private void isValidQty(int qty) {
        if (qty < 0) {
            throw new IllegalArgumentException("Quality should be positive!");
        }
    }

    public int add(int qty) {

        isValidQty(qty);
        qtyOnHand = qtyOnHand + qty;
        return qtyOnHand;

    }

    public int deduct(int qty) {

        isValidQty(qty);

        int newQty = qtyOnHand - qty;
        if (newQty < 0) {
            throw new IllegalArgumentException("Out of Stock!");
        } else {
            qtyOnHand = newQty;
        }
        return qtyOnHand;

    }

}

3.3ユニットテストの下では、PItestによって生成されたすべての突然変異が殺されます。

TestStockService.java

package com.mkyong.examples;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestStockService {

    @DisplayName("Test deduct stock")
    @Test
    public void testDeduct() {
        StockService obj = new StockService(100);
        assertEquals(90, obj.deduct(10));
        assertEquals(0, obj.deduct(90));
        assertEquals(0, obj.deduct(0));

        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            obj.deduct(-1);
        });

        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            obj.deduct(100);
        });

    }

    @DisplayName("Test add stock")
    @Test
    public void testAdd() {
        StockService obj = new StockService(100);
        assertEquals(110, obj.add(10));
        assertEquals(110, obj.add(0));

        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            obj.add(-1);
        });
    }


}

3.4それを実行します。

$ mvn clean org.pitest:pitest-maven:mutationCoverage

#or

$ mvn clean test

3.5 `target \ pit-reports \ $ {YYYYMMDDHHMI} \ index.html`のレポートを見直してください

image

image

4.よくある質問

4.1 PITest Mutators を調べて、突然変異がどのように生成されるかを理解する。

4.2この突然変異検査は時間がかかる作業であり、常に突然変異検査に必要なクラスを宣言します。

pom.xml

    <plugin>
        <groupId>org.pitest</groupId>
        <artifactId>pitest-maven</artifactId>
        <version>${pitest.version}</version>

        <configuration>
            <targetClasses>
                <param>com.mkyong.examples.** Calculator** </param>
                <param>com.mkyong.examples.** Stock** </param>
            </targetClasses>
            <targetTests>
                <param>com.mkyong.examples.** </param>
            </targetTests>
        </configuration>
    </plugin>

ソースコードをダウンロードする

$ gitクローンhttps://github.com/mkyong/maven-examples.git $ cd maven-mutation-testing

$ mvn clean org.pitest:pitest-maven:mutationCoverage#または$ mvnクリーンテスト

#target/pit-reports/YYYYMMDDHHMI/index.htmlのレポートを表示する

参考文献

テスト]。リンク://maven/maven-jacoco-code-coverage-example/[Maven - JaCoCoコード

カバレッジの例]

リンク://タグ/コードカバレッジ/[コードカバレッジ]リンク://タグ/junit-5/[junit 5] maven 突然変異検査 pitest unit test