1. 程式人生 > >JAVA程式碼覆蓋率工具JaCoCo-原理簡單分析

JAVA程式碼覆蓋率工具JaCoCo-原理簡單分析

作為一個測試人員,保證產品的軟體質量是其工作首要目標,為了這個目標,測試人員常常會通過很多手段或工具來加以保證,覆蓋率就是其中一環比較重要的環節。

我們通常會將測試覆蓋率分為兩個部分,即“需求覆蓋率”和“程式碼覆蓋率”。

需求覆蓋:指的是測試人員對需求的瞭解程度,根據需求的可測試性來拆分成各個子需求點,來編寫相應的測試用例,最終建立一個需求和用例的對映關係,以用例的測試結果來驗證需求的實現,可以理解為黑盒覆蓋。

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

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

如果做覆蓋率測試?我們可以藉助一些網上流行的各種覆蓋率工具,本章主要介紹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.0
Premain-Class: com.shanhy.demo.agent.MyAgent
Can-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包後,會生成動態覆蓋資訊到檔案,最後統一對覆蓋資訊進行處理,並生成報告。

On-the-fly和offline比較:

On-the-fly模式更方便簡單進行程式碼覆蓋分析,無需提前進行位元組碼插樁,無需考慮classpath 的設定。

存在如下情況不適合on-the-fly,需要採用offline提前對位元組碼插樁:

(1)執行環境不支援java agent。

(2)部署環境不允許設定JVM引數。

(3)位元組碼需要被轉換成其他的虛擬機器如Android Dalvik VM。

(4)動態修改位元組碼過程中和其他agent衝突。

(5)無法自定義使用者載入類。

2. JaCoCo執行最小的java版本

最小需要Java1.5

3. 位元組碼處理方式

JaCoCo通過注入來修改和生成java位元組碼,使用的是ASM庫。

4. java方法控制流分析

JaCoCo是如何在位元組碼注入的?

先舉個例項,有個java方法:

編譯後轉換成位元組碼後,內容如下:

我們知道JaCoCo是位元組碼注入方式,它是通過一個Probe探針的方式來注入的,具體如下:

探針是位元組指令集插入到java方法中,程式執行後可以被記錄,它不會改變原有程式碼的行為。

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

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

JaCoCo是根據控制流Type來採用不同的探針插入策略的。

一個用java位元組碼定義的java方法的控制流圖可能有以下的type,每一個type連線一個源指令與目標指令,type不同探針的注入策略也會不同,如下是type定義:



相關推薦

JAVA程式碼覆蓋率工具JaCoCo-原理簡單分析

作為一個測試人員,保證產品的軟體質量是其工作首要目標,為了這個目標,測試人員常常會通過很多手段或工具來加以保證,覆蓋率就是其中一環比較重要的環節。 我們通常會將測試覆蓋率分為兩個部分,即“需求覆蓋率”和“程式碼覆蓋率”。 需求覆蓋:指的是測試人員對需求的瞭解程度,根據

JAVA 程式碼覆蓋率工具 JaCoCo-原理

一、 覆蓋率定義 作為一個測試人員,保證產品的軟體質量是其工作首要目標,為了這個目標,測試人員常常會通過很多手段或工具來加以保證,覆蓋率就是其中一環比較重要的環節。 我們通常會將測試覆蓋率分為兩個部分,即“需求覆蓋率”和“程式碼覆蓋率”。 需求覆蓋:指的是測試人

JAVA程式碼覆蓋率工具JaCoCo-實踐篇

一、覆蓋率專案中使用介紹 本節開始詳細介紹下專案中的JaCoCo實戰經驗。 下圖是覆蓋率在實際在專案中的主要實施點: 分別詳細介紹下: 1.1 確定插樁方式 Android專案只能使用JaCoCo的離線插樁方式。 為什麼?主要是因為Android覆蓋率的特殊性

JAVA程式碼覆蓋率工具JaCoCo-踩坑篇

一、覆蓋率踩過的坑 在專案中使用JaCoCo覆蓋率的時候,也遇到過各種奇葩的問題,在這裡列出來分享下,問題和實際的專案關係密切,希望對有遇到過相似問題的童鞋有所啟發。 1.1 覆蓋率包在部分手機6.0上安裝失敗 事情起因:在測試新功能時,用打的覆蓋率包,外包反饋部分手機6.0上安裝不了。 問題重現:

【騰訊TMQ】JAVA程式碼覆蓋率工具JaCoCo-踩坑篇

作者:劉洋 一、覆蓋率踩過的坑 在專案中使用JaCoCo覆蓋率的時候,也遇到過各種奇葩的問題,在這裡列出來分享下,問題和實際的專案關係密切,希望對有遇到過相似問題的童鞋有所啟發。 1.1 覆蓋率包在部分手機6.0上安裝失敗 事情起因:在測試新功

JAVA 程式碼覆蓋率工具 JaCoCo-踩坑篇

一、覆蓋率踩過的坑在專案中使用JaCoCo覆蓋率的時候,也遇到過各種奇葩的問題,在這裡列出來分享下,問題和實際的專案關係密切,希望對有遇到過相似問題的童鞋有所啟發。1.1 覆蓋率包在部分手機6.0上安裝失敗事情起因:在測試新功能時,用打的覆蓋率包,外包反饋部分手機6.0上安裝

AVA 程式碼覆蓋率工具 JaCoCo-實踐篇

一、覆蓋率專案中使用介紹本節開始詳細介紹下專案中的JaCoCo實戰經驗。下圖是覆蓋率在實際在專案中的主要實施點:分別詳細介紹下:1.1 確定插樁方式Android專案只能使用JaCoCo的離線插樁方式。為什麼?主要是因為Android覆蓋率的特殊性:一般執行在伺服器java程

JaCoCo 程式碼覆蓋率工具(基於Maven+TestNG)

JaCoco是一個程式碼覆蓋率庫。 安裝:  以 Maven(http://www.testclass.net/maven/) 安裝為例: <dependencies> <dependency> <gro

Java 內部類實現原理簡單分析

轉載:原文地址http://www.fzhen.info/?p=300 本文重點不在與內部類的語法及使用,而是試圖解釋一些背後的原理。 內部類簡介 Java支援在類內部定義類,即為內部類。 普通內部類 把類的定義放在類的內部,例如: 程式碼清單1: public class Outer{ priv

JaCoCo 程式碼覆蓋率工具(基於Maven+TestNG)

JaCoco是一個程式碼覆蓋率庫。 安裝: 以 Maven(http://www.testclass.net/maven/) 安裝為例: <dependencies> <dependency> <groupId>org.test

Java靜態檢測工具/Java程式碼規範和質量檢查簡單介紹

靜態檢查: 靜態測試包括程式碼檢查、靜態結構分析、程式碼質量度量等。它可以由人工進行,充分發揮人的邏輯思維優勢,也可以藉助軟體工

Java簡單實驗--關於課後提到的java重載函數的簡單分析

-- bsp png ron inf 定義 方法返回值 http 分享 根據這一小段代碼,獲得了以下的測試截圖: 簡單分析:根據輸出結果,判斷這段代碼用到了兩個不同的函數方法,輸出的不止有double類型的數,還有整型的數。 又根據類中的定義情況,square是根據

java程式碼-Exccel工具

package com.ufc.utils; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStrea

DWM1000 測距原理簡單分析

DWM1000 超寬頻測距,使用的TOF(time of fly) 的方式,也就是計算無線電磁波傳輸時間,通過傳輸的時間換算成距離。 電磁波傳輸速率和光速一樣,速度是299792.458km/s,可參見百度百科。如果想通過測試這個傳播時間換算距離,那麼就需要非常高的內部時鐘。然。。。並不是有了高速的內部時鐘即

java動態代理實現與原理詳細分析(【轉載】By--- Gonjan )

【轉載】By---    Gonjan    關於Java中的動態代理,我們首先需要了解的是一種常用的設計模式--代理模式,而對於代理,根據建立代理類的時間點,又可以分為靜態代理和動態代理。  一、代理模式  

java動態代理實現與原理詳細分析(【轉載】By--- Gonjan )

sleep class 實施 div prot stack 註意 san 由於 【轉載】By--- Gonjan 關於Java中的動態代理,我們首先需要了解的是一種常用的設計模式--代理模式,而對於代理,根據創建代理類的時間點,又可以分為靜態代理和動態代理。

Java工具推薦】Generator:Java程式碼生成工具

歡迎來到 Generator 寫這個程式碼生成器工具的想法源自2018年3月份,當時專案組剛完成一個Java Web專案的研發工作,在整個專案過程中耗費了不少的時間來構建SpringMVC的重複性程式碼和Mybatis的對映檔案,同時我也越來越覺得這些重複且難度不大的工作不

java動態代理實現與原理詳細分析

generator result title super java args 設計 需要 edt 關於Java中的動態代理,我們首先需要了解的是一種常用的設計模式--代理模式,而對於代理,根據創建代理類的時間點,又可以分為靜態代理和動態代理。 一、代理模式 代理模式

NAT-T技術原理簡單分析及應用實驗解析

1.首先我們就IPSEC VPN的部署場景來做簡要分析: 場景1:如圖所示,企業的總部與分支機構分別架設了VPN裝置,分支機構的需求是同步企業內部的業務資料(屬企業內部的機密資訊),那麼就必須確保資料在公網上是安全包密傳遞的。這種情況下我們可以直接用IPSEC

Spring MVC 典型分層Java程式碼生成工具

本文目的: 企業應用開發實際過程中必不可少的步驟是對資料庫表進行增刪查改,相應的java程式碼基本實現都需要不停拼接資料庫欄位。為了減少程式設計師重複勞動,本文嘗試編寫工具類基於資料表字段生成基本的java的實體類模板,controller類模板,ser