基于 Jenkins + JaCoCo 實現(xiàn)功能測試代碼覆蓋率統(tǒng)計
本文對 JaCoCo 進行簡要介紹,并借助 Jenkins 實現(xiàn)功能測試代碼覆蓋率統(tǒng)計
使用 JaCoCo 統(tǒng)計功能測試代碼覆蓋率昆稿?
對于 JaCoCo纺座,有所了解但又不是很熟悉。 “有所了解”指的是在 CI 實踐中已經(jīng)使用 JaCoCo 對單元測試代碼覆蓋率統(tǒng)計: 當代碼 push 到代碼倉庫后溉潭,用 JaCoCo 進行單元測試代碼覆蓋率統(tǒng)計净响,并將相應(yīng)數(shù)據(jù)推送到 SonarQube。 “不是很熟”指的是應(yīng)用場景也僅限于此喳瓣,并未進行過多研究與實踐馋贤。
前不久,有測試同事提出夫椭,想要在實際測試時掸掸,用 JaCoCo 統(tǒng)計功能測試代碼覆蓋率。 其主要目的是在經(jīng)過功能測試后蹭秋,通過查看代碼覆蓋率統(tǒng)計的相關(guān)指標扰付,增強對軟件質(zhì)量的信心。 經(jīng)查閱資料仁讨,證明這是可行的羽莺。
由于對 JaCoCo 不甚了解,于是查閱官網(wǎng)資料對 JaCoCo 進一步了解洞豁。
進一步了解 JaCoCo
JaCoCo盐固,即 Java Code Coverage,是一款開源的 Java 代碼覆蓋率統(tǒng)計工具丈挟。 它由 EclEmma 團隊根據(jù)多年來使用和集成現(xiàn)有庫的經(jīng)驗教訓而創(chuàng)建刁卜。
JaCoCo 愿景
JaCoCo 應(yīng)該為基于 Java VM 的環(huán)境中的代碼覆蓋率分析提供標準技術(shù)。 重點是提供一個輕量級的曙咽、靈活的蛔趴、文檔良好的庫,以便與各種構(gòu)建和開發(fā)工具集成例朱。
JaCoCo 產(chǎn)品功能
指令(C0)孝情、分支(C1)、行洒嗤、方法箫荡、類型和圈復雜度的覆蓋率分析。
基于 Java 字節(jié)碼渔隶,因此也可以在沒有源文件的情況下工作羔挡。
通過基于 Java agent 的實時檢測進行簡單集成。其他集成場景(如自定義類加載器)也可以通過 API 實現(xiàn)。
框架無關(guān)性:平穩(wěn)地與基于 Java VM 的應(yīng)用程序集成婉弹,比如普通 Java 程序睬魂、OSGi 框架、web 容器或 EJB 服務(wù)器镀赌。
兼容所有已發(fā)布的 Java 類文件版本氯哮。
支持不同的 JVM 語言。
支持幾種報告格式( HTML商佛、XML喉钢、CSV )。
遠程協(xié)議和 JMX 控件良姆,以便在任何時間點從覆蓋率 agent 請求執(zhí)行數(shù)據(jù) dump 肠虽。
Ant 任務(wù),用于收集和管理執(zhí)行數(shù)據(jù)并創(chuàng)建結(jié)構(gòu)化覆蓋報告玛追。
Maven 插件税课,用于收集覆蓋信息并在Maven構(gòu)建中創(chuàng)建報告。
非功能特性
使用簡單和與現(xiàn)有構(gòu)建腳本和工具集成痊剖。
良好的性能和最小的運行時開銷韩玩,特別是對大型項目。
輕量級實現(xiàn)陆馁,對外部庫和系統(tǒng)資源的依賴性最小找颓。
全面的文檔。
完整文檔化的 API ( JavaDoc ) 和用于與其他工具集成的示例叮贩。
回歸測試基于 JUnit 測試用例击狮,具有完整的功能測試覆蓋率。
對 JaCoCo 可以與現(xiàn)有構(gòu)建腳本和工具進行集成這里做進一步說明: 官方提供了 Java API益老、Java Agent 彪蓬、CLI、Ant 捺萌、Maven寞焙、Eclipse 這幾種集成方式; 第三方提供了諸如與 Gradle互婿、IDEA、Jenkins 等其它工具的集成方式辽狈。
拋開理論慈参,開始實踐
JaCoCo 不僅支持統(tǒng)計本地服務(wù)的代碼覆蓋率,也支持統(tǒng)計遠程服務(wù)的代碼覆蓋率刮萌。 單元測試覆蓋率統(tǒng)計就是統(tǒng)計本地服務(wù)的代碼覆蓋率驮配,代碼和運行的服務(wù)在一臺機器上,筆者這里通過使用 JaCoCo Maven 插件完成的。 而功能測試代碼覆蓋率統(tǒng)計則是統(tǒng)計遠程服務(wù)的代碼覆蓋率壮锻,代碼和運行的服務(wù)一般不在一臺機器上琐旁,這里需要借助 JaCoCo Java agent 實現(xiàn)。 > 備注:實際上猜绣,JaCoCo Maven 插件也使用了 JaCoCo Java agent灰殴,不過用戶不需要直接關(guān)系 Java agent 及其選項,Maven 插件都透明地處理了掰邢。
1牺陶、下載 JaCoCo 分發(fā)包
可以從 JaCoCo 官網(wǎng)下載分發(fā)包,也可以從 Maven 倉庫(中央倉庫或私服)下載辣之。 分發(fā)包的 lib 目錄下掰伸,包括以下庫:
2、Java 應(yīng)用啟動腳本添加 jacocoagent 相關(guān) JVM 參數(shù)
需要將 jacocoagent.jar 推送到部署應(yīng)用的服務(wù)器上怀估,筆者這里用 Ansible 進行了批量推送狮鸭。 Java 應(yīng)用啟動腳本需要加入類似下面的 JVM 參數(shù):
JAVA_OPTS="$JAVA_OPTS -javaagent:/path/jacocoagent.jar=includes=*,output=tcpserver,append=false,address=$IP,port=$JACOCO_PORT"
這樣在應(yīng)用成功啟動后,會暴露一個 TCP 服務(wù)多搀,客戶端可以連接到這個服務(wù)并獲取執(zhí)行數(shù)據(jù)文件歧蕉。
相關(guān)屬性說明如下: - append:其中 append=false 表示 dump 每次會生成一個新的執(zhí)行數(shù)據(jù)文件,如果 append=true酗昼,dump 時則會將數(shù)據(jù)追加到已存在的執(zhí)行數(shù)據(jù)文件廊谓。 其中 output=tcpserver 表示 agent 監(jiān)聽來自被 adrress 和 port 屬性指定的TCP 端口的連接,執(zhí)行數(shù)據(jù)被寫到這個連接麻削; - output:如果 output=tcpclient 則表示在啟動時蒸痹,agent 連接到被 adrress 和 port 屬性指定的TCP 端口,執(zhí)行數(shù)據(jù)被寫到這個連接呛哟; 如果 output=file 則表示在 JVM 終止時叠荠,執(zhí)行數(shù)據(jù)被寫到被 destfile 屬性指定的文件。output 默認值為 file 扫责。 - address:當 output 為 tcpserver 時綁定到的 IP 地址或主機名榛鼎,或者當 output 為 tcpclient 時連接到的 IP 地址或主機名。 在 tcpserver 模式下鳖孤,值為“*”導致代理只接受本機地址上的連接者娱。address 默認值為 127.0.0.1 。 - port:當 output 方式為 tcpserver 時綁定到該端口苏揣,或者當 output 方式為 tcpclient 時連接到該端口黄鳍。 在 tcpserver 模式下,端口必須可用平匈,這意味著如果多個 JaCoCo agent 在同一臺機器上運行框沟,則必須指定不同的端口藏古。port 默認值為 6300 。
3忍燥、創(chuàng)建及配置 Jenkins Pipeline 任務(wù)
Jenkins 任務(wù)大致有幾個步驟:拉取代碼拧晕,構(gòu)建,dump 應(yīng)用執(zhí)行數(shù)據(jù)( jacoco.exec )梅垄,解析 JaCoCo 產(chǎn)生的 jacoco.exec 文件厂捞,然后生成覆蓋率報告(HTML 格式)。 拉取代碼這里無需多說哎甲,配置下從代碼倉庫(SVN/Git)和分支地址就可以了蔫敲,比較簡單。 構(gòu)建這里用了 Jenkins Pipeline Maven Integration Plugin 炭玫,筆者這里所用的 Maven 命令是 mvn clean package -Dmaven.test.skip=true 奈嘿。 dump 應(yīng)用執(zhí)行數(shù)據(jù)這里有多種方式:Ant、CLI吞加、Maven裙犹,因為Java 應(yīng)用是用 Maven 構(gòu)建的,這里選擇了 Maven Jacoco Plugin衔憨。 解析 JaCoCo 產(chǎn)生的 jacoco.exec 文件叶圃,然后生成覆蓋率報告(HTML 格式)筆者這里使用了 Jenkins Jacoco Plugin。
Jenkins Pipeline 案例如下:
pipeline {
? ? agent any
? ? tools {
? ? ? ? jdk 'JDK1.8'
? ? }
? ? stages {
? ? ? ? stage('Checkout'){
? ? ? ? ? ? steps{
? ? ? ? ? ? ? ? git branch: '${GIT_BRANCH}', credentialsId: 'xxx-xxx-xx-xx-xxx', url: '${GIT_URL}'
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? stage('Build') {
? ? ? ? ? ? steps{
? ? ? ? ? ? ? ? withMaven(maven: 'maven'){
? ? ? ? ? ? ? ? ? ? ? sh "mvn clean package -Dmaven.test.skip=true"
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? stage('DumpFromServer'){
? ? ? ? ? ? steps {
? ? ? ? ? ? ? ? withMaven(maven: 'maven'){
? ? ? ? ? ? ? ? ? ? ? sh 'mvn org.jacoco:jacoco-maven-plugin:0.8.4:dump -Djacoco.address=${SERVER_IP} -Djacoco.port=${JACOCO_PORT}'
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? stage('JacocoPublisher') {
? ? ? ? ? ? steps {
? ? ? ? ? ? ? ? jacoco()
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
JaCoCo 覆蓋率報告践图,部分截圖如下:
總結(jié)
筆者所實現(xiàn)的方式并未覆蓋任何場景掺冠,但是大同小異,相關(guān)工具的使用詳情可以查看官網(wǎng)文檔码党,因為它是最全面的德崭。 筆者希望這個實踐能給有類似訴求的同行一些參考,當然筆者也希望能夠和大家互相交流揖盘。 同時筆者的 JaCoCo 實踐之路并未結(jié)束眉厨,可能在使用的過程中會有一些問題需要解決, 后續(xù)也將考慮使用 Jenkins API 為需要統(tǒng)計功能測試代碼覆蓋率的 Java 應(yīng)用實例自動生成一個對應(yīng)的 Jenkins 任務(wù)兽狭, 并在 Java 應(yīng)用實例銷毀后憾股,對相應(yīng)的 Jenkins 任務(wù)進行清理等其它功能。
參考
https://www.eclemma.org/jacoco/index.html
https://www.jacoco.org/jacoco/trunk/doc/integrations.html
https://www.jacoco.org/jacoco/trunk/doc/agent.html
https://www.jacoco.org/jacoco/trunk/doc/counters.html
https://www.eclemma.org/jacoco/trunk/doc/mission.html