程式碼覆蓋率(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中增加以下2個外掛,分別用於TestNG測試執行和Jacoco覆蓋率統計。
<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>
下面我們編寫一個被測試的Java類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構建的test生命週期中執行。
<?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生命週期中執行(pom.xml中不配置phase的goal,會預設使用外掛的設定),用於準備代理(你可以理解為向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 # 一些引數