JVM插码之六:jacoco插码及问题“$jacocodata 属性 Method not found: is$jacocoData”
在使用jacoco統計自動化代碼覆蓋率
jacoco統計自動化代碼覆蓋率
1. 簡介
1.1. 什么是Jacoco
Jacoco是一個開源的代碼覆蓋率工具,可以嵌入到Ant 、Maven中,并提供了EclEmma Eclipse插件,也可以使用JavaAgent技術監控Java程序。很多第三方的工具提供了對Jacoco的集成,如sonar、Jenkins等。
1.2. 什么是代碼覆蓋率
代碼覆蓋(Code coverage)是軟件測試中的一種度量,描述程式中源代碼被測試的比例和程度,所得比例稱為代碼覆蓋率。
代碼覆蓋率是衡量測試質量的一個重要指標。在對一個軟件產品進行了單元測試、組裝測試、集成測試以及接口測試等繁多的測試之后,我們能不能就此對軟件的質量產生一定的信心呢?這就需要我們對測試的質量進行考察。如果測試僅覆蓋了代碼的一小部分,那么不管我們寫了多少測試用例,我們也不能相信軟件質量是有保證的。相反,如果測試覆蓋到了軟件的絕大部分代碼,我們就能對軟件的質量有一個合理的信心。
代碼覆蓋分為下面五種情況:
1.2.1. 函數覆蓋
函數覆蓋(Function Coverage),執行到程序中的每一個函數(或副程式)。
1.2.2. 語句覆蓋
語句覆蓋(Statement Coverage),又稱行覆蓋(Line Coverage),段覆蓋(Segment Coverage),基本塊覆蓋(Basic Block Coverage),這是最常用也是最常見的一種覆蓋方式,就是度量被測代碼中每個可執行語句是否被執行到了。這里說的是“可執行語句”,因此就不會包括像C++的頭文件聲明,代碼注釋,空行,等等。非常好理解,只統計能夠執行的代碼被執行了多少行。需要注意的是,單獨一行的花括號{}也常常被統計進去。語句覆蓋常常被人指責為“最弱的覆蓋”,它只管覆蓋代碼中的執行語句,卻不考慮各種分支的組合等等。假如你的上司只要求你達到語句覆蓋,那么你可以省下很多功夫,但是,換來的確實測試效果的不明顯,很難更多地發現代碼中的問題。
1.2.3. 判斷覆蓋
判斷覆蓋(Decision Coverage),又稱分支覆蓋(Branch Coverage),所有邊界覆蓋(All-Edges Coverage),基本路徑覆蓋(Basic Path Coverage),判定路徑覆蓋(Decision-Decision-Path)。它度量程序中每一個判定的分支是否都被測試到了。這句話是需要進一步理解的,應該非常容易和下面說到的條件覆蓋混淆。因此我們直接介紹第三種覆蓋方式,然后和判定覆蓋一起來對比,就明白兩者是怎么回事了。
1.2.4. 條件覆蓋
條件覆蓋(Condition Coverage),它度量判定中的每個子表達式結果true和false是否被測試到了。
1.2.5. 路徑覆蓋
路徑覆蓋(Path Coverage),又稱斷言覆蓋(Predicate Coverage)。它度量了是否函數的每一個分支都被執行了。 這句話也非常好理解,就是所有可能的分支都執行一遍,有多個分支嵌套時,需要對多個分支進行排列組合,可想而知,測試路徑隨著分支的數量指數級別增加。
1.3. Jacoco的功能
1.3.1. 覆蓋率計數器
Jacoco使用一系列的不同的計數器來做覆蓋率的度量計算。所有這些計數器都是從java的class文件中獲取信息,這些class文件可以(可選)包含調試的信息在里面。即使在沒有源碼的情況下,這種方法也可以實時有效地對應用程序進行度量和分析。在大部分情況下,收集到的信息可以映射到源碼,可視化到每一行代碼的粒度。但這種方法還是有一些限制。這些class文件必須使用調試信息來編譯,這樣才可以計算行的覆蓋率和提供出源碼的高亮。但不是所有的JAVA語言的結構都可以直接編譯成一致的二進制代碼。在這種情況下,java 編譯器會創建所謂的“合成”代碼,會導致產生一些不期望得到的覆蓋率結果。
1.3.2. 指令覆蓋率
Jacoco最小的計數單元是單個java二進制代碼指令。指令覆蓋率提供了代碼是否被執行的信息。這個度量完全獨立源碼格式,并且總是可用,即使class文件里面沒有調試信息。
1.3.3. 分支覆蓋率
Jacoco也計算分支的覆蓋率,包括所有的if和switch語句。這個度量計算一個方法里面的總分支數,確定執行和不執行的分支數量。分支覆蓋率總是可用的,即使class文件里面沒有調試信息。注意異常處理是不在分支度量里面統計的。
2、部署
自動化測試接口時,利用jacoco的agent統計覆蓋率,部署方法是在jvm啟動命令行里增加如下命令:
-Djava.awt.headless=true -javaagent:D:\AutoTest\jacoco\lib\jacocoagent.jar=includes=com.hundsun.*,output=tcpserver,port=8229,address=127.0.0.1 -Xverify:none問題:
org.springframework.data.mongodb.UncategorizedMongoDbException: Query failed with error code 2 and error message 'unknown top level operator: $jacocoData'?
?原因是,封裝的mongo的API里利用反射對查詢參數的自動化拼接查詢語句,在啟動了jacoco后,dto里插碼了jacocoData屬性,被反射組裝成查詢語句了。
解決辦法:
后來問了部署jacoco服務的框架組人員,發現是用了java Agent在修改運行時字節碼實現的,拉了dump發現確實在運行時進行字節碼修改的,而在jacoco官方的github也曾經有過這個問題的issue:
jacocoData
即使用了是否為復合字段的field方法解決。即在反射的組裝位置通過isSynthetic的判斷如果為false,說明是插碼的屬性,不處理即可。
總結
以上是生活随笔為你收集整理的JVM插码之六:jacoco插码及问题“$jacocodata 属性 Method not found: is$jacocoData”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM插码之五:Java agent+A
- 下一篇: 实战渗透 | 向吃鸡外挂站开炮