程式碼覆蓋率(Code coverage)用於描述一次測試執行中,被執行的程式碼佔總程式碼的比率。這裡的一次執行,可以是一次單元測試,也可以是一段時間內的手工測試執行;覆蓋率除了按程式碼行進行計算,也可以統計程式程式碼的分支、函式和類的覆蓋率。
Jacoco是一款流行的開源Java程式碼覆蓋率工具,常見的覆蓋率有以下幾個:
- 指令 Instructions
針對Java位元組程式碼指令的覆蓋,是Jacoco最小粒度的指標。它提供被執行和遺漏的程式碼數量資訊。
- 分支 Branches
基於If、Switch語句帶來的分支來計算覆蓋率,不包括異常處理分支。提供檔案、類、方法3個層面的統計。
- 行、方法和類
針對原始碼的中的行、方法和類,進行被執行、遺漏、以及總數的統計。
下面我們給出一個例子,展示如何在Maven執行單元測試時,使用Jacoco統計程式碼覆蓋率。完整原始碼可參考這裡。
新建一個基於Maven的TestNG單元測試專案,在pom.xml中加入以下依賴。
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.uncommons</groupId>
<artifactId>reportng</artifactId>
<version>1.1.4</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</exclusion>
</exclusions>
</dependency>
在pom.xml中加入以下外掛。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
<suiteXmlFiles>
<suiteXmlFile>${testng.suite}</suiteXmlFile>
</suiteXmlFiles>
<argLine> @{argLine} -Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.9</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
下面我們編寫一個被測試的類Count。
package com.deeptest.sample.jcoco;
public class Count {
public int add(int x ,int y){
int i = 0;
if (i == 0) {
i++;
} else {
i--;
}
return x + y;
}
public int sub(int x ,int y){
return x - y;
}
public int div(int x ,int y){
return x / y;
}
}
再寫一個TestNG測試類。
package com.deeptest.sample.jcoco;
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
public class CountTest {
@Test
public void testAdd() {
Count count = new Count();
int result = count.add(2,2);
assertEquals(result, 4);
}
}
在src/test/res中建立一個如下的測試套件,它被上述pom.xml中名為maven-surefire-plugin的外掛所引用,預設會被maven作為單元測試的套件執行。
<?xml version="1.0" encoding="UTF-8"?>
<suite name="套件">
<test name="用例">
<classes>
<class name="com.deeptest.sample.jcoco.CountTest" />
</classes>
</test>
</suite>
進入專案根目錄,執行以下命令開始測試。
mvn clean test
結束後jacoco會在target/site/jacoco下生成XML和HTML格式的覆蓋率報告,其中HTML報告開啟如下。
最後我們花點時間,給大家介紹下maven構建的過程。在pom.xml我們定義了兩個外掛,分別用於jacoco的執行和java程式碼的打包。
這裡重點介紹下jacoco-maven-plugin外掛,其下名為prepare-agent的goal,在maven的initialize生命週期中執行,用於準備代理(你可以理解為向Java虛機注入程式碼,掛上獲取VM執行資訊的鉤子);名為report的goal,用於在測試完成後,生成覆蓋率報告。
如果不使用pom.xml的execution執行器,也可以用命令來代替。注意:以下是一個單行命令,為了註釋分成了多行。
mvn clean -Dmaven.test.skip=false # 不忽略測試
org.jacoco:jacoco-maven-plugin:0.8.9:prepare-agent # 準備Jacoco代理
compile test-compile # 編譯程式碼
org.apache.maven.plugins:maven-surefire-plugin:2.22.1:test # 單元測試
org.apache.maven.plugins:maven-jar-plugin:2.4:jar # 打包JAR
org.jacoco:jacoco-maven-plugin:0.8.9:report # 生成Jacoco覆蓋率報告
-Dmaven.test.failure.ignore=true -Dfile.encoding=UTF-8 # 一些引數