作為一個測試人員,保證產品的軟體品質是其工作首要目標,為了這個目標,測試人員常常會通過很多手段或工具來加以保證,覆蓋率就是其中一環比較重要的環節。
我們通常會將測試覆蓋率分為兩個部分,即“需求覆蓋率”和“程式碼涵蓋範圍”。
需求覆蓋:指的是測試人員對需求的瞭解程度,根據需求的可測試性來拆分成各個子需求點,來編寫相應的測試案例,最終建立一個需求和用例的映射關係,以用例的測試結果來驗證需求的實現,可以理解為黑盒覆蓋。
代碼覆蓋:為了更加全面的覆蓋,我們可能還需要理解被測程式的邏輯,需要考慮到每個函數的輸入與輸出,邏輯分支代碼的執行情況,這個時候我們的測試執行情況就以程式碼涵蓋範圍來衡量,可以理解為白盒覆蓋。
以上兩者完全可以相輔相成,用代碼覆蓋結果反向的檢查需求覆蓋(用例)的測試是否充分完整。
如果做覆蓋率測試。我們可以藉助一些網上流行的各種覆蓋率工具,本章主要介紹JaCoCo這個工具。
EMMA與JaCoco比較分析:
市場上java主要程式碼涵蓋範圍工具:EMMA、JaCoCo
總結一下個人對JaCoCo優勢的理解:
(1)JaCoCo支援分支覆蓋、引入了Agent模式。
(2)EMMA官網已經不維護了,JaCoCo是其團隊開發的,可以理解為一個升級版。
(3)JaCoCo社區比較活躍,官網也在不斷的維護更新。
JaCoCo是一個開源的覆蓋率工具(官網地址:http://www.eclemma.org/JaCoCo/),它針對的開發語言是java,其使用方法很靈活,可以嵌入到Ant、Maven中;可以作為Eclipse外掛程式,可以使用其JavaAgent技術監控Java程式等等。
##############################如果你不瞭解什麼是java agent,下面接著有介紹,否則直接跳過####################################
JavaAgent 是JDK 1.5 以後引入的,也可以叫做Java代理。
JavaAgent 是運行在 main方法之前的攔截器,它內定的方法名叫 premain ,也就是說先執行 premain 方法然後再執行 main 方法。
那麼如何?一個 JavaAgent 呢。很簡單,只需要增加 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方法之前運行,與main方法運行在同一個JVM中 * 並被同一個System ClassLoader裝載 * 被統一的安全性原則(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方法執行========"); System.out.println(agentOps); } /** * 如果不存在 premain(String agentOps, Instrumentation inst) * 則會執行 premain(String agentOps) * * @param agentOps * @author SHANHY * @create 2016年3月30日 */ public static void premain(String agentOps) { System.out.println("=========premain方法執行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
寫完這個類後,我們還需要做一步配置工作。
在 src 目錄下添加 META-INF/MANIFEST.MF 檔案,內容按如下定義:
Manifest-Version: 1.0Premain-Class: com.shanhy.demo.agent.MyAgentCan-Redefine-Classes: true
1 2 3 4 1 2 3 4
要特別注意,一共是四行,第四行是空行,還有就是冒號後面的一個空格,如下截圖:
然後我們打包代碼為 myagent.jar
注意打包的時候選擇我們自己定義的 MANIFEST.MF
接著我們在建立一個帶有main方法的主程式工程,截圖如下:
然後將該主程式打包為 myapp.jar
如何執行 myagent.jar 。我們通過 -javaagent 參數來指定我們的Java代理包,值得一說的是 -javaagent 這個參數的個數是不限的,如果指定了多個,則會按指定的先後執行,執行完各個 agent 後,才會執行主程式的 main 方法。
命令如下:
java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -javaagent:G:\myagent.jar=Hello3 -jar myapp.jar
1 1
輸出結果:
G:\>java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -javaagent:G:\myagent.jar=Hello3 -jar myapp.jar=========premain方法執行========Hello1=========premain方法執行========Hello2=========premain方法執行========Hello3=========main方法執行========
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
特別提醒:如果你把 -javaagent 放在 -jar 後面,則不會生效。也就是說,放在主程式後面的 agent 是無效的。
比如執行:
java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -jar myapp.jar -javaagent:G:\myagent.jar=Hello3
1 1
只會有前個生效,第三個是無效的。
輸出結果:
G:\>java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -jar myapp.jar -javaagent:G:\myagent.jar=Hello3=========premain方法執行========Hello1=========premain方法執行========Hello2=========main方法執行========
1 2 3 4 5 6 1 2 3 4 5 6
命令中的Hello1為我們傳遞給 premain 方法的字串參數。
至此,我們會使用 javaagent 了,但是單單看這樣啟動並執行效果,好像沒有什麼實際意義嘛。
我們可以用 javaagent 做什麼呢。下篇文章我們來介紹如何在項目中應用 javaagent。
最後說一下,還有一種,在main方法執行後再執行代理的方法,因為不常用,而且主程式需要配置 Agent-Class,所以不常用,如果需要自行瞭解下 agentmain(String agentArgs, Instrumentation inst) 方法。
#################################################### java agent介紹結束 #####################################################
很多第三方的工具提供了對JaCoCo的整合,如sonar、Jenkins等。
JaCoCo包含了多種尺度的覆蓋率計數器,包含指令級覆蓋(Instructions,C0coverage),分支(Branches,C1coverage)、循環複雜度(CyclomaticComplexity)、行覆蓋(Lines)、方法覆蓋(non-abstract methods)、類覆蓋(classes)。
行覆蓋率:度量被測程式的每行代碼是否被執行,判斷標準行中是否至少有一個指令被執行。
類覆蓋率:度量計算class類檔案是否被執行。
分支覆蓋率:度量if和switch語句的分支覆蓋情況,計算一個方法裡面的
總分支數,確定執行和不執行的 分支數量。
方法覆蓋率:度量被測程式的方法執行情況,是否執行取決於方法中是否有至少一個指令被執行。
指令覆蓋:計數單元是單個java二進位代碼指令,指令覆蓋率提供了代碼是否被執行的資訊,度量完全 獨立源碼格式。
循環複雜度:在(線性)組合中,計算在一個方法裡面所有可能路徑的最小數目,缺失的複雜度同樣表示測 試案例沒有完全覆蓋到這個模組。
jacoco原理:
1. 注入方式介紹
這個圖包含了幾種不同的收集覆蓋率資訊的方法,每種方法的實現方法都不一樣,帶顏色的部分是JaCoCo比較有特色的地方。
上面各個名次含義(帶顏色的為JaCoCo支援):
上表JaCoCo支援的部分,再詳細的解釋下:
(1)JaCoCo在Byte Code時使用的ASM技術修改位元組碼方法,可以修改Jar檔案、class檔案位元組碼檔案。
(2)JaCoCo同時支援on-the-fly和offline的兩種插樁模式。 On-the-fly插樁:
JVM中通過-javaagent參數指定特定的jar檔案啟動Instrumentation的代理程式,代理程式在通過Class Loader裝載一個class前判斷是否轉換修改class檔案,將統計代碼插入class,測試覆蓋率分析可以在JVM執行測試代碼的過程中完成。 Offline模式:
在測試前先對檔案進行插樁,然後產生插過樁的class或jar包,測試插過樁 的class和jar包後,會產生動態覆蓋資訊到檔案,最後統一對覆蓋資訊進行處理,並產生報告。