前言
對於大多數 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.xml
的 packaging
屬性改為 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
參考資料: