日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA代码覆盖率工具JaCoCo-原理简单分析

發(fā)布時(shí)間:2023/12/19 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA代码覆盖率工具JaCoCo-原理简单分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

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

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

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

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

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

EMMA與JaCoco比較分析:

市場(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ì)開發(fā)的,可以理解為一個(gè)升級(jí)版。

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

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

##############################如果你不了解什么是java agent,下面接著有介紹,否則直接跳過####################################

JavaAgent 是JDK 1.5 以后引入的,也可以叫做Java代理。

JavaAgent 是運(yùn)行在 main方法之前的攔截器,它內(nèi)定的方法名叫 premain ,也就是說先執(zhí)行 premain 方法然后再執(zhí)行 main 方法。

那么如何實(shí)現(xiàn)一個(gè) JavaAgent 呢?很簡(jiǎn)單,只需要增加 premain 方法即可。

看下面的代碼和代碼中的注釋說明:

package com.shanhy.demo.agent;import java.lang.instrument.Instrumentation;/*** 我的Java代理** @author 單紅宇(365384722)* @myblog http://blog.csdn.net/catoop/* @create 2016年3月30日*/ public class MyAgent {/*** 該方法在main方法之前運(yùn)行,與main方法運(yùn)行在同一個(gè)JVM中* 并被同一個(gè)System ClassLoader裝載* 被統(tǒng)一的安全策略(security policy)和上下文(context)管理** @param agentOps* @param inst* @author SHANHY* @create 2016年3月30日*/public static void premain(String agentOps, Instrumentation inst) {System.out.println("=========premain方法執(zhí)行========");System.out.println(agentOps);}/*** 如果不存在 premain(String agentOps, Instrumentation inst) * 則會(huì)執(zhí)行 premain(String agentOps)** @param agentOps* @author SHANHY* @create 2016年3月30日*/public static void premain(String agentOps) {System.out.println("=========premain方法執(zhí)行2========");System.out.println(agentOps);} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

寫完這個(gè)類后,我們還需要做一步配置工作。

在 src 目錄下添加 META-INF/MANIFEST.MF 文件,內(nèi)容按如下定義:

Manifest-Version: 1.0 Premain-Class: com.shanhy.demo.agent.MyAgent Can-Redefine-Classes: true
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

要特別注意,一共是四行,第四行是空行,還有就是冒號(hào)后面的一個(gè)空格,如下截圖:?

然后我們打包代碼為 myagent.jar

注意打包的時(shí)候選擇我們自己定義的 MANIFEST.MF?


接著我們?cè)趧?chuàng)建一個(gè)帶有main方法的主程序工程,截圖如下:?

然后將該主程序打包為 myapp.jar


如何執(zhí)行 myagent.jar ?我們通過 -javaagent 參數(shù)來指定我們的Java代理包,值得一說的是 -javaagent 這個(gè)參數(shù)的個(gè)數(shù)是不限的,如果指定了多個(gè),則會(huì)按指定的先后執(zhí)行,執(zhí)行完各個(gè) agent 后,才會(huì)執(zhí)行主程序的 main 方法。

命令如下:

java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -javaagent:G:\myagent.jar=Hello3 -jar myapp.jar
  • 1
  • 1

輸出結(jié)果:

G:\>java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -javaagent:G:\myagent.jar=Hello3 -jar myapp.jar =========premain方法執(zhí)行======== Hello1 =========premain方法執(zhí)行======== Hello2 =========premain方法執(zhí)行======== Hello3 =========main方法執(zhí)行========
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

特別提醒:如果你把 -javaagent 放在 -jar 后面,則不會(huì)生效。也就是說,放在主程序后面的 agent 是無效的。

比如執(zhí)行:

java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -jar myapp.jar -javaagent:G:\myagent.jar=Hello3
  • 1
  • 1

只會(huì)有前個(gè)生效,第三個(gè)是無效的。?
輸出結(jié)果

G:\>java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -jar myapp.jar -javaagent:G:\myagent.jar=Hello3 =========premain方法執(zhí)行======== Hello1 =========premain方法執(zhí)行======== Hello2 =========main方法執(zhí)行========
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

命令中的Hello1為我們傳遞給 premain 方法的字符串參數(shù)。

至此,我們會(huì)使用 javaagent 了,但是單單看這樣運(yùn)行的效果,好像沒有什么實(shí)際意義嘛。

我們可以用 javaagent 做什么呢?下篇文章我們來介紹如何在項(xiàng)目中應(yīng)用 javaagent。


最后說一下,還有一種,在main方法執(zhí)行后再執(zhí)行代理的方法,因?yàn)椴怀S?#xff0c;而且主程序需要配置 Agent-Class,所以不常用,如果需要自行了解下 agentmain(String agentArgs, Instrumentation inst) 方法。

#################################################### java agent介紹結(jié)束 #####################################################


很多第三方的工具提供了對(duì)JaCoCo的集成,如sonar、Jenkins等。
JaCoCo包含了多種尺度的覆蓋率計(jì)數(shù)器,包含指令級(jí)覆蓋(Instructions,C0coverage),分支(Branches,C1coverage)、圈復(fù)雜度(CyclomaticComplexity)、行覆蓋(Lines)、方法覆蓋(non-abstract methods)、類覆蓋(classes)。

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

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

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

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

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

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

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


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

Offline模式:

在測(cè)試前先對(duì)文件進(jìn)行插樁,然后生成插過樁的class或jar包,測(cè)試插過樁 的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)行代碼覆蓋分析,無需提前進(jìn)行字節(jié)碼插樁,無需考慮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é)碼過程中和其他agent沖突。

(5)無法自定義用戶加載類。

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

最小需要Java1.5

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

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

4. java方法控制流分析

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

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

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

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

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

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

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

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

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





總結(jié)

以上是生活随笔為你收集整理的JAVA代码覆盖率工具JaCoCo-原理简单分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。