JAVA代碼覆蓋率工具JaCoCo-原理篇

https://blog.csdn.net/TMQ1225/article/details/52221187?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control

JAVA代碼覆蓋率工具JaCoCo-原理篇

一、 覆蓋率定義

作為一個(gè)測(cè)試人員,保證產(chǎn)品的軟件質(zhì)量是其工作首要目標(biāo),為了這個(gè)目標(biāo),測(cè)試人員常常會(huì)通過(guò)很多手段或工具來(lái)加以保證,覆蓋率就是其中一環(huán)比較重要的環(huán)節(jié)。

我們通常會(huì)將測(cè)試覆蓋率分為兩個(gè)部分,即“需求覆蓋率”和“代碼覆蓋率”。

需求覆蓋:指的是測(cè)試人員對(duì)需求的了解程度,根據(jù)需求的可測(cè)試性來(lái)拆分成各個(gè)子需求點(diǎn),來(lái)編寫(xiě)相應(yīng)的測(cè)試用例,最終建立一個(gè)需求和用例的映射關(guān)系,以用例的測(cè)試結(jié)果來(lái)驗(yàn)證需求的實(shí)現(xiàn),可以理解為黑盒覆蓋。

代碼覆蓋:為了更加全面的覆蓋,我們可能還需要理解被測(cè)程序的邏輯,需要考慮到每個(gè)函數(shù)的輸入與輸出,邏輯分支代碼的執(zhí)行情況,這個(gè)時(shí)候我們的測(cè)試執(zhí)行情況就以代碼覆蓋率來(lái)衡量,可以理解為白盒覆蓋。

以上兩者完全可以相輔相成,用代碼覆蓋結(jié)果反向的檢查需求覆蓋(用例)的測(cè)試是否充分完整。

如果做覆蓋率測(cè)試?我們可以借助一些網(wǎng)上流行的各種覆蓋率工具,本章主要介紹JaCoCo這個(gè)工具。

二、JAVA覆蓋率工具介紹

市場(chǎng)上java主要代碼覆蓋率工具:EMMA、JaCoCo

總結(jié)一下個(gè)人對(duì)JaCoCo優(yōu)勢(shì)的理解:

(1)JaCoCo支持分支覆蓋、引入了Agent模式。

(2)EMMA官網(wǎng)已經(jīng)不維護(hù)了,JaCoCo是其團(tuán)隊(duì)開(kāi)發(fā)的,可以理解為一個(gè)升級(jí)版。

(3)JaCoCo社區(qū)比較活躍,官網(wǎng)也在不斷的維護(hù)更新。

我們前期使用的EMMA,也做了全量、差異覆蓋率,和精準(zhǔn)耦合也結(jié)合在了一起,但后來(lái)考慮到JaCoCo的優(yōu)勢(shì),也就全部切換了過(guò)來(lái)。

2.1 JaCoCo簡(jiǎn)述

JaCoCo是一個(gè)開(kāi)源的覆蓋率工具(官網(wǎng)地址:http://www.eclemma.org/JaCoCo/),它針對(duì)的開(kāi)發(fā)語(yǔ)言是java,其使用方法很靈活,可以嵌入到Ant、Maven中;可以作為Eclipse插件,可以使用其JavaAgent技術(shù)監(jiān)控Java程序等等。

很多第三方的工具提供了對(duì)JaCoCo的集成,如sonar、Jenkins等。

JaCoCo包含了多種尺度的覆蓋率計(jì)數(shù)器,包含指令級(jí)覆蓋(Instructions,C0coverage),分支(Branches,C1coverage)、圈復(fù)雜度(CyclomaticComplexity)、行覆蓋(Lines)、方法覆蓋(non-abstract methods)、類(lèi)覆蓋(classes),后面會(huì)一一介紹。

我們先看看其覆蓋率結(jié)果展現(xiàn)如下圖1-1所示,方便讀者先有一個(gè)大概的了解。

圖1-1 覆蓋率報(bào)告結(jié)果部分截圖??

標(biāo)示綠色的為行覆蓋充分,標(biāo)紅色的為未覆蓋的行,黃色菱形的為分支部分覆蓋,綠色菱形為分支完全覆蓋。

通過(guò)這個(gè)報(bào)告的結(jié)果就可以知道代碼真實(shí)的執(zhí)行情況,便于我們分析評(píng)估結(jié)果。

2.2 JaCoCo基本概念

行覆蓋率:度量被測(cè)程序的每行代碼是否被執(zhí)行,判斷標(biāo)準(zhǔn)行中是否至少有一個(gè)指令被執(zhí)行。

類(lèi)覆蓋率:度量計(jì)算class類(lèi)文件是否被執(zhí)行。

分支覆蓋率:度量if和switch語(yǔ)句的分支覆蓋情況,計(jì)算一個(gè)方法里面的

總分支數(shù),確定執(zhí)行和不執(zhí)行的 分支數(shù)量。

方法覆蓋率:度量被測(cè)程序的方法執(zhí)行情況,是否執(zhí)行取決于方法中是否有至少一個(gè)指令被執(zhí)行。

指令覆蓋:計(jì)數(shù)單元是單個(gè)java二進(jìn)制代碼指令,指令覆蓋率提供了代碼是否被執(zhí)行的信息,度量完全 獨(dú)立源碼格式。

圈復(fù)雜度:在(線(xiàn)性)組合中,計(jì)算在一個(gè)方法里面所有可能路徑的最小數(shù)目,缺失的復(fù)雜度同樣表示測(cè) 試案例沒(méi)有完全覆蓋到這個(gè)模塊。

2.3 JaCoCo 原理

1. 注入方式介紹

這個(gè)圖包含了幾種不同的收集覆蓋率信息的方法,每種方法的實(shí)現(xiàn)方法都不一樣,帶顏色的部分是JaCoCo比較有特色的地方。

上面各個(gè)名次含義(帶顏色的為JaCoCo支持):

上表JaCoCo支持的部分,再詳細(xì)的解釋下:

(1)JaCoCo在Byte Code時(shí)使用的ASM技術(shù)修改字節(jié)碼方法,可以修改Jar文件、class文件字節(jié)碼文件。

(2)JaCoCo同時(shí)支持on-the-fly和offline的兩種插樁模式。

On-the-fly插樁:

JVM中通過(guò)-javaagent參數(shù)指定特定的jar文件啟動(dòng)Instrumentation的代理程序,代理程序在通過(guò)Class Loader裝載一個(gè)class前判斷是否轉(zhuǎn)換修改class文件,將統(tǒng)計(jì)代碼插入class,測(cè)試覆蓋率分析可以在JVM執(zhí)行測(cè)試代碼的過(guò)程中完成。

Offline模式:

在測(cè)試前先對(duì)文件進(jìn)行插樁,然后生成插過(guò)樁的class或jar包,測(cè)試插過(guò)樁 的class和jar包后,會(huì)生成動(dòng)態(tài)覆蓋信息到文件,最后統(tǒng)一對(duì)覆蓋信息進(jìn)行處理,并生成報(bào)告。

On-the-fly和offline比較:

On-the-fly模式更方便簡(jiǎn)單進(jìn)行代碼覆蓋分析,無(wú)需提前進(jìn)行字節(jié)碼插樁,無(wú)需考慮classpath 的設(shè)置。

存在如下情況不適合on-the-fly,需要采用offline提前對(duì)字節(jié)碼插樁:

(1)運(yùn)行環(huán)境不支持java agent。

(2)部署環(huán)境不允許設(shè)置JVM參數(shù)。

(3)字節(jié)碼需要被轉(zhuǎn)換成其他的虛擬機(jī)如Android Dalvik VM。

(4)動(dòng)態(tài)修改字節(jié)碼過(guò)程中和其他agent沖突。

(5)無(wú)法自定義用戶(hù)加載類(lèi)。

2. JaCoCo執(zhí)行最小的java版本

最小需要Java1.5

3. 字節(jié)碼處理方式

JaCoCo通過(guò)注入來(lái)修改和生成java字節(jié)碼,使用的是ASM庫(kù)。

4. java方法控制流分析

JaCoCo是如何在字節(jié)碼注入的?

我們帶著疑問(wèn)來(lái)看下面的內(nèi)容:

先舉個(gè)實(shí)例,有個(gè)java方法:

編譯后轉(zhuǎn)換成字節(jié)碼后,內(nèi)容如下:

我們知道JaCoCo是字節(jié)碼注入方式,它是通過(guò)一個(gè)Probe探針的方式來(lái)注入的,具體如下:

探針是字節(jié)指令集插入到j(luò)ava方法中,程序執(zhí)行后可以被記錄,它不會(huì)改變?cè)写a的行為。

我們看看探針前后插入比較:

顏色的部分就是探針注入的地方。

JaCoCo是根據(jù)控制流Type來(lái)采用不同的探針插入策略的。

一個(gè)用java字節(jié)碼定義的java方法的控制流圖可能有以下的type,每一個(gè)type連接一個(gè)源指令與目標(biāo)指令,type不同探針的注入策略也會(huì)不同,如下是type定義:

探針不改變?cè)摲椒ǖ男袨?,但記錄他們已被?zhí)行的事實(shí),從理論上講,可以在控制流圖的每一個(gè)邊插入一個(gè)探針,作為探針實(shí)現(xiàn)本身需要多個(gè)字節(jié)碼指令,這將增加幾倍的類(lèi)文件的大小和執(zhí)行速度。

事實(shí)上,只需要一個(gè)幾個(gè)探頭,根據(jù)每個(gè)方法的控制流的方法,下面說(shuō)明了如何在不同的邊緣類(lèi)型的情況下添加額外的指令:

一個(gè)instrumented class可以用以下代碼檢索其探針數(shù)組實(shí)例:

JaCoCo是用一個(gè)布爾數(shù)組來(lái)實(shí)現(xiàn)探針,每個(gè)探針對(duì)應(yīng)于該數(shù)組中的項(xiàng)。當(dāng)以下四個(gè)字節(jié)碼指令觸發(fā)時(shí)探針進(jìn)行輸入設(shè)置為true:

JaCoCo對(duì)行探針是這樣處理的,添加兩行指令之間的一個(gè)額外的探針時(shí),后續(xù)行至少包含一個(gè)方法調(diào)用。

以上是JaCoCo插樁原理,如果想深入了解,可以去看看它的源碼實(shí)現(xiàn)。

三、JaCoCo使用方式

使用方式有很多,這里貼出了相應(yīng)的參考鏈接,根據(jù)項(xiàng)目的不同可以靈活供有需要的讀者去學(xué)習(xí)。

3.1 Apache Ant方式

參見(jiàn) http://eclemma.org/jacoco/trunk/doc/ant.html

主要有以下幾種,具體使用就不介紹了,應(yīng)用寶是用的這種方式,后續(xù)有介紹。

Task coverage、Task agent、Task dump、Task merge、Task report、Task instrument

3.2 命令行方式

參見(jiàn) http://www.eclemma.org/jacoco/trunk/doc/agent.html

使用方式說(shuō)明:

主要放在JAVA_OPTS中,比如:

由AgentOptions的getVMArgument方法加載,各參數(shù)入AgentOptions的對(duì)應(yīng)參數(shù),為后續(xù)操作做為輸入。

下面是官網(wǎng)的所有參數(shù)說(shuō)明:

系統(tǒng)在jvm停止的時(shí)候會(huì)dump覆蓋率信息。

關(guān)鍵的核心代碼在這里,Agent.java在有一段代碼

Runtime.getRuntime().addShutdownHook這個(gè)方法的意思就是在jvm中增加一個(gè)關(guān)閉的鉤子,當(dāng)jvm關(guān)閉的時(shí)候,會(huì)執(zhí)行系統(tǒng)中已經(jīng)設(shè)置的所有通過(guò)方法addShutdownHook添加的鉤子,當(dāng)系統(tǒng)執(zhí)行完這些鉤子后,jvm才會(huì)關(guān)閉。所以這些鉤子可以在jvm關(guān)閉的時(shí)候進(jìn)行內(nèi)存清理、對(duì)象銷(xiāo)毀等操作。

也就是在JVM關(guān)閉的時(shí)候調(diào)用agent.shutdown(),也就是寫(xiě)覆蓋率數(shù)據(jù)。

3.3 Apache Maven方式

參見(jiàn) http://www.eclemma.org/jacoco/trunk/doc/maven.html

這種方式適合Maven的項(xiàng)目。

下面簡(jiǎn)單說(shuō)下調(diào)用方式原理:

就拿官方的Offline Example來(lái)說(shuō)吧,其內(nèi)容如下:

注意藍(lán)色的部分,上面的配置主要做了以下幾個(gè)事情:

(1)項(xiàng)目已jar包方式打包,引入junit和jacoco。

(2)Build時(shí)執(zhí)行instrument、report、check。

(3)覆蓋率生成到target/jacoco.exec

我們看看他是怎么觸發(fā)調(diào)用的。

在jacoco源碼中:jacoco-maven-plugin\target\classes\META-INF\maven\org.jacoco\jacoco-maven-plugin目錄下有個(gè)plugin-help.xml文件,它里面標(biāo)明了具體的調(diào)用方式。

截出instrument這段,關(guān)鍵地方就是下面藍(lán)色部分。

官網(wǎng)上關(guān)于參數(shù)的說(shuō)明:

給出一個(gè)整理后的表格:

再給一個(gè)jacoco的maven部分的代碼目錄:

到這里,大家應(yīng)該清楚其調(diào)用的方式了吧。

3.4 Eclipse EclDmma Plugin方式

具體步驟如下:

(1)在Eclipse菜單中選擇Help → Install New Software…

(2)在安裝彈框中輸入http://update.eclemma.org/,勾選出現(xiàn)的版本。

(3)核對(duì)版本,點(diǎn)擊Next。

(4)根據(jù)向?qū)瓿砂惭b。

(5)使用就不說(shuō)了。

3.5 與Jekins集成

(1)先要在jenkins上安裝JaCoCo的插件,安裝完成之后在job的配置項(xiàng)中可以增加這個(gè)選項(xiàng)(如圖1-2):

圖1-2

(2)選擇后出現(xiàn)(圖1-3):

圖1-3

第一個(gè)錄入框是你的覆蓋率文件(exec),第二個(gè)是class文件目錄,第三個(gè)是源代碼文件目錄。

(3)配置好了之后進(jìn)行構(gòu)建,構(gòu)建完成之后job首頁(yè)就會(huì)出現(xiàn)覆蓋率的趨勢(shì)圖(圖1-4),鼠標(biāo)點(diǎn)擊趨勢(shì)圖可以看到覆蓋率詳情(圖1-5) ,包括具體覆蓋率數(shù)據(jù)和源碼的覆蓋率情況:

圖1-4 趨勢(shì)圖

圖1-5 覆蓋率詳情

JaCoCo原理篇就介紹到這里了,后續(xù)還有項(xiàng)目實(shí)踐篇和踩坑篇,實(shí)踐篇主要介紹下JaCoCo在實(shí)際業(yè)務(wù)中的使用情況,踩坑篇里面包含了幾個(gè)當(dāng)時(shí)遇到的比較棘手的問(wèn)題的解決思路,有興趣的童鞋請(qǐng)關(guān)注。

本章完~

原文鏈接:http://tmq.qq.com/2016/08/java-code-coverage-tools-jacoco-principle/

————————————————

版權(quán)聲明:本文為CSDN博主「騰訊移動(dòng)品質(zhì)中心TMQ」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/TMQ1225/article/details/52221187

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容