JaCoCo是面向Java的開源代碼覆蓋率工具,JaCoCo以Java代理模式運行,它負責在運行測試時檢測字節碼。 JaCoCo會深入研究每個指令,並顯示每個測試過程中要執行的行。 為了收集覆蓋率數據,JaCoCo使用ASM即時進行代碼檢測,並在此過程中從JVM Tool Interface接收事件,最終生成代碼覆蓋率報告。

jacoco運行有離線(offline)、在線(on the fly)模式之說,所謂在線模式就是在應用啟動時加入jacoco agent進行插樁,在開發、測試人員使用應用期間實時地進行代碼覆蓋率分析。相信很多的java項目開發人員並不會去寫單元測試代碼的,因此覆蓋率統計就要把手工測試或接口測試覆蓋的情況作為重要依據,顯然在線模式更符合實際需求,本文以在線模式為例進行演示。
Jacoco安裝
從官網
https://www.jacoco.org/jacoco/下載最新版本並解壓到指定目錄

主要用到如下二個jar包:

在線模式jacoco覆蓋率統計包含三個步驟:
- 啟動應用增加jacoco agent進行插樁,該步驟會啟動TCP Server。
- 從TCP Server dump生成代碼覆蓋率文件,生成的文件格式為.exec格式的二級制文件。
- 解析.exec格式文件生成html格式代碼覆蓋率報告。
准備Java示例代碼
事先需要創建java示例代碼,本文不聚焦java代碼相關的內容,大家可以使用自己的java項目代碼進行驗證,或者直接clone本文提供的spring boot示例代碼倉庫
https://gitee.com/pepperpapa/jacoco_demo。
注意:在線模式使用的代碼一定要是類似web應用這種永遠不會退出的程序為例,因為收集jacoco agent要啟用tcp server,如果程序執行完就退出了tpc server也關閉了。
![]()
示例代碼就是提供兩個簡單的URL訪問,訪問截圖如下:
執行構建命令mvn clean package后,會在target目錄生成可運行的jar包
啟動jacoco agent進行插樁
打開cmd,cd到示例代碼的target目錄,執行如下命令:
java -javaagent:C:/Users/yuanw/Desktop/jacoco/lib/jacocoagent.jar=includes=*,output=tcpserver,port=6300,address=localhost,append=true -jar demo-0.0.1-SNAPSHOT.jar
關鍵參數說明:
- -javaagent:C:\工具\jacoco-0.8.6\lib\jacocoagent.jar=includes=*,這個參數就是啟用jacoco代理參數,其中C:\工具\jacoco-0.8.6\lib\jacocoagent.jar就是之前下載jacoco解壓后的jacocoagent.jar的絕對路徑,includes表示對要插樁的包進行過濾,*代表所有的class都要進行插樁,也可以根據情況進行過濾,如includes=com.mycompany.*
- output=tcpserver,這里不需要改動,表示以TCP Server方式啟動應用並插樁
- port=6300,Jacoco開啟的TCP Server的端口,不能被占用
- address=localhost,對外開放的地址,也可以指定IP地址
- demo-0.0.1-SNAPSHOT.jar,就是示例代碼構建后target目錄生成的jar包,需要根據實際情況更新
執行后就會啟動web服務,截圖如下:
特別提醒:為了對比實時統計代碼覆蓋率的效果,此時請先不要請求上面提到的任何一個URL,切記!dump生成覆蓋率文件
保持服務啟動,再打開一個cmd窗口同樣cd到target目錄,執行如下命令從上一步開啟的TCP Server中dump出覆蓋率文件
java -jar C:/Users/yuanw/Desktop/jacoco/lib/jacococli.jar dump --address localhost --port 6300 --destfile ./jacoco_tcp_01.exec參數說明:
- --destfile ./jacoco_tcp.exec,其中./jacoco_tcp.exec為生成exec文件名,表示在當前目錄生成
- 其他參數和上一步類似,不再特別說明,注意需要更新jacococli.jar的絕對路徑
執行成功后,會在target目錄生成相應的.exec文件
接下來,我們在瀏覽器中訪問該web示例應用提供的兩個
UR---http://127.0.0.1:8080/hello、http://127.0.0.1:8080/byebye,應用會調用相應的方法並正常返回結果。然后,我們再次執行dump命令再生成一個.exec文件,命名為jacoco_tcp_02.exec
java -jar C:/Users/yuanw/Desktop/jacoco/lib/jacococli.jar dump --address localhost --port 6300 --destfile ./jacoco_tcp_02.exec
分析exec文件生成html報告
dump命令生成的.exec文件為二進制文件,需要進行解析,以生成html報告為例,執行如下的命令分別將兩個.exec文件解析成html報告
java -jar C:/Users/yuanw/Desktop/jacoco/lib/jacococli.jar report ./jacoco_tcp_01.exec --classfiles ./classes --sourcefiles ../src\main/java --html report01
java -jar C:/Users/yuanw/Desktop/jacoco/lib/jacococli.jar report ./jacoco_tcp_01.exec --classfiles ./classes --sourcefiles ../src/main/java --html report02參數說明:
- ./jacoco_tcp_01.exec,表示要解析的exec文件的相對路徑
- --classfiles .\classes,需要指定生成的classes文件目錄,參見下圖
- --sourcefiles ..\src\main\java,需要指定源碼的文件目錄,參見下圖
最終,target目錄會生成report01、report02兩個目錄,分別打開其中的index.html查看代碼覆蓋率結果。
我們發現report01中的代碼覆蓋率為73%,其中say()和bybye()兩個方法沒有被覆蓋:
而我們訪問了對應的服務之后生成的report02覆蓋率報告為100%,say()和bybye()這兩個方法都覆蓋到了:
![]()
覆蓋率指標說明
- Instructions: Java 字節指令的覆蓋率。執行的最小單位,和代碼的格式無關。
- Branches: 分支覆蓋率。注意,異常處理不算做分支。
- Cxty(Cyclomatic Complexity): 圈復雜度, Jacoco 會為每一個非抽象方法計算圈復雜度,並為類,包以及組(groups)計算復雜度。圈復雜度簡單地說就是為了覆蓋所有路徑,所需要執行單元測試數量,圈復雜度大說明程序代碼可能質量低且難於測試和維護。
- Lines: 行覆蓋率,只要本行有一條指令被執行,則本行則被標記為被執行。
- Methods: 方法覆蓋率,任何非抽象的方法,只要有一條指令被執行,則該方法就會被計為被執行。
- Classes: 類覆蓋率,所有類,包括接口,只要其中有一個方法被執行,則標記為被執行。注意:構造函數和靜態初始化塊也算作方法。










