基於Jacoco的單元測試程式碼覆蓋率統計

陳琦發表於2023-05-04

程式碼覆蓋率(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報告開啟如下。
image.png

最後我們花點時間,給大家介紹下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     # 一些引數

專題目錄

相關文章