maven 多模組專案的測試覆蓋率分析

2023-03-10 06:01:17

前言

對於大多數 maven 多模組化工程,可以使用 Jacoco 這款工具,關於 Jacoco 這款工具,ChatGPT 對它的描述是這樣的:

JaCoCo(Java Code Coverage)是一個開源的測試覆蓋率工具,它可以用於幫助開發人員衡量其軟體測試的有效性。它支援多種語言,包括 Java 和 Kotlin 等,並且可以與多個構建工具和整合式開發環境(IDE)一起使用。

JaCoCo 可以收集測試覆蓋率資料,並生成視覺化的測試覆蓋率報告,幫助開發人員更好地理解其程式碼的測試覆蓋率情況。它提供了多種測試覆蓋率指標,例如行覆蓋率、分支覆蓋率、方法覆蓋率、類覆蓋率等,可以幫助開發人員瞭解其測試覆蓋率情況的具體細節。

JaCoCo 還可以與多種構建工具整合,例如 Maven、Gradle 等。它可以通過 Maven 或 Gradle 的外掛來收集測試覆蓋率資料,並在構建過程中生成測試覆蓋率報告

Jacoco 可以很好的支援對 Maven 多模組進行聚合分析測試覆蓋率,可以從專案整體輸出覆蓋率報告非常方便。

下面展示一下具體的使用方法

一:建立根專案

先建立一個多模組的 Maven 專案,大致的結構如下:

├── parent-project
├── pom.xml
├── business-module1
│   ├── pom.xml
│   └── src
│       ├── main
│       └── test
├── business-module2
│   ├── pom.xml
│   └── src
│       ├── main
│       └── test
└── test-module
    ├── pom.xml
    └── src
        ├── main
        └── test

在一個空白的目錄,一個的 Maven 的根專案:

mvn archetype:generate \
-DgroupId=org.example \
-DartifactId=jacoco-multi-module-example \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

然後進入目錄:

cd jacoco-multi-module-example

把根目錄 pom.xmlpackaging 屬性改為 pom,從而將根目錄設定為一個聚合模組,用來管理多個子模組的依賴關係

<packaging>pom</packaging>

二:建立子模組

根據上面的結構,在根目錄下,分別建立:

  • business-module1
  • business-module2
  • test-module

在根目錄的路徑下,輸入以下命令,建立 business-module1 模組:

mvn archetype:generate \
-DgroupId=org.example \
-DartifactId=business-module1 \
-DarchetypeArtifactId=maven-archetype-quickstart  \
-DinteractiveMode=false

建立 business-module2 模組:

mvn archetype:generate \
-DgroupId=org.example \
-DartifactId=business-module2 \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

建立 test-module 單元測試模組:

mvn archetype:generate \
-DgroupId=org.example \
-DartifactId=test-module \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

然後模擬實際的開發,分別在模組1,模組2中新增一些業務程式碼,

business-module1 中我新增一個簡單的數學運算 IntegerSimpleCompute 類:

// business-module1\src\main\java\org\example\IntegerSimpleCompute.java
package org.example;

public class IntegerSimpleCompute {

    public int add(int i, int j) {
        return i + j;
    }

    public int subtract(int i, int j) {
        return i - j;
    }

    public int multiply(int i, int j) {
        return i * j;
    }

    public int divide(int i, int j) {
        return i / j;
    }
}

business-module2 中我新增一個簡單的邏輯運算 IntegerLogicCompute 類:

// business-module2\src\main\java\org\example\IntegerLogicCompute.java
package org.example;

public class IntegerLogicCompute {

    public int increment(Integer i) {
        return i + 1;
    }

    public int decrement(Integer i) {
        return i- 1;
    }

    // 存在條件分支的語句,需要滿足所有條件分支判斷才能達到 100% 的覆蓋率
    public boolean equals(Integer i, Integer j) {
        if (i < 127 && j < 127) {
            return i == j;
        }
        return i.equals(j);
    }
}

三:建立測試模組

我們將 test-module 作為測試模組,在該模組的 pom.xml 檔案中,我們引入上面的測試模組,方便對他們進行整合測試

<dependencies>
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>business-module1</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>business-module2</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

然後在 src/test/java 目錄下建立測試類:

// test-module\src\test\java\org\example\IntegrationTest.java
package org.example;

import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class IntegrationTest {

    private IntegerSimpleCompute simpleCompute;
    private IntegerLogicCompute logicCompute;

    @Before
    public void init() {
        simpleCompute = new IntegerSimpleCompute();
        logicCompute = new IntegerLogicCompute();
    }

    @Test
    public void simpleComputeTest() throws Throwable {
        assertEquals(7, simpleCompute.add(3, 4));
        assertEquals(4, simpleCompute.subtract(7, 3));
        assertEquals(12, simpleCompute.multiply(3, 4));
        assertEquals(3, simpleCompute.divide(12, 4));
    }

    @Test
    public void logicComputeTest() throws Throwable {
        assertEquals(8, logicCompute.increment(7));
        assertEquals(6, logicCompute.decrement(7));
        assertEquals(true, logicCompute.equals(125, 125));
        assertEquals(false, logicCompute.equals(123, 125));
        assertEquals(false, logicCompute.equals(123, 130));
        assertEquals(false, logicCompute.equals(133, 125));
        assertEquals(true, logicCompute.equals(140, 140));
        assertEquals(false, logicCompute.equals(140, 141));
    }
}

到可以,你可以通過:

mvn test

執行單元測試,maven 的 maven-surefire-plugin 外掛也會簡單的輸出如下測試報告:

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

四:生成覆蓋率報告

首先在根目錄的 pom.xml 引入 jacoco 外掛並且啟動代理:

<build>
    <plugins>
        <!-- 指定 Java 編譯版本 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>11</source>
                <target>11</target>
            </configuration>
        </plugin>

        <!-- jacoco 外掛 -->
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.8</version>
            <executions>
                <!--  執行 prepare-agent 目標,它會啟動 JaCoCo 代理 -->
                <execution>
                    <id>default-prepare-agent</id>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                </execution>

                <!-- 執行 mvn verify 時,生成測試覆蓋率報告 -->
                <execution>
                    <id>report</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

然後在 test-module 模組中引入 jacoco 外掛,宣告一個聚合分析任務:

<build>
    <plugins>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.8</version>
            <executions>
                <!--  在執行 mvn verify 時,生成聚合測試覆蓋率報告,所有 Maven 子模組的測試覆蓋率資料 -->
                <execution>
                    <id>report-aggregate</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>report-aggregate</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

最後在根目錄執行指令,執行所有測試:

$ mvn clean verify

構建成功後可以在 test-module 模組下的 target/site/jacoco-aggregate/index.html 檢視覆蓋率報告:

點選對應模組可以看到包內部所有類,方法還有每一行的測試覆蓋率情況,這裡具體不再展開,自己可以嘗試以下

範例程式碼:jacoco-module-sample

參考資料: