JaCoCo在Tomcat服務器上監控代碼覆蓋率的使用方法


簡介

Jacoco是一個開源的覆蓋率工具。Jacoco可以嵌入到Ant 、Maven中,並提供了EclEmma Eclipse插件,也可以使用JavaAgent技術監控Java程序。很多第三方的工具提供了對Jacoco的集成,如sonar、Jenkins等。

官網地址:http://www.eclemma.org/jacoco/

Jacoco包含了多種尺度的覆蓋率計數器,包含指令級(Instructions,C0coverage),分支(Branches,C1coverage)、圈復雜度(CyclomaticComplexity)、行(Lines)、方法(non-abstract methods)、類(classes)。

²  行覆蓋率:度量被測程序的每行代碼是否被執行,判斷標准行中是否至少有一個指令被執行。

²  類覆蓋率:度量計算class類文件是否被執行。

²  分支覆蓋率:度量if和switch語句的分支覆蓋情況,計算一個方法里面的總分支數,確定執行和不執行的分支數量。

²  方法覆蓋率:度量被測程序的方法執行情況,是否執行取決於方法中是否有至少一個指令被執行。

²  指令覆蓋:計數單元是單個java二進制代碼指令,指令覆蓋率提供了代碼是否被執行的信息,度量完全 獨立源碼格式。

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

目前支持的啟動類型:

²  Local Java application java程序(有main)

²  Eclipse/RCP application 桌面應用程序

²  Equinox OSGi framework

²  JUnit test 單元測試

²  TestNG test

²  JUnit plug-in test

²  JUnit RAP test

²  SWTBot test

²  Scala application

 

覆蓋率工具工作流程

 

1. 對Java字節碼進行插樁,On-The-Fly和Offine兩種方式。 
2. 執行測試用例,收集程序執行軌跡信息,將其dump到內存。 
3. 數據處理器結合程序執行軌跡信息和代碼結構信息分析生成代碼覆蓋率報告。 
4. 將代碼覆蓋率報告圖形化展示出來,如html、xml等文件格式。

 

插樁原理

 

主流代碼覆蓋率工具都采用字節碼插樁模式,通過鈎子的方式來記錄代碼執行軌跡信息。其中字節碼插樁又分為兩種模式On-The-Fly和Offine。On-The-Fly模式優點在於無需修改源代碼,可以在系統不停機的情況下,實時收集代碼覆蓋率信息。Offine模式優點在於系統啟動不需要額外開啟代理,但是只能在系統停機的情況下才能獲取代碼覆蓋率。

On-The-Fly插樁 Java Agent

 

1、JVM中通過-javaagent參數指定特定的jar文件啟動Instrumentation的代理程序
2、代理程序在每裝載一個class文件前判斷是否已經轉換修改了該文件,如果沒有則需要將探針插入class文件中。
3、代碼覆蓋率就可以在JVM執行代碼的時候實時獲取。
4、典型代表:Jacoco

On-The-Fly插樁 Class Loader

1、自定義classloader實現自己的類裝載策略,在類加載之前將探針插入class文件中

2、典型代表:Emma

Offine插樁

1、在測試之前先對文件進行插樁,生成插過樁的class文件或者jar包,執行插過樁的class文件或者jar包之后,會生成覆蓋率信息到文件,最后統一對覆蓋率信息進行處理,並生成報告。
2、Offline插樁又分為兩種:
       1》Replace:修改字節碼生成新的class文件
       2》Inject:在原有字節碼文件上進行修改
3、典型代表:Cobertura

On-The-Fly和Offine比較

1、On-The-Fly模式更加方便的獲取代碼覆蓋率,無需提前進行字節碼插樁,可以實時獲取代碼覆蓋率信息
2、Offline模式適用於以下場景:
          運行環境不支持java agent
          部署環境不允許設置JVM參數
          字節碼需要被轉換成其他虛擬機字節碼,如Android Dalvik VM
          動態修改字節碼過程中和其他agent沖突
          無法自定義用戶加載類

 

JaCoCo作用

監測應用程序在測試時有多少源碼被執行。

測試包括:單元測試、功能測試、接口測試
執行包括:指令、分支、圈復雜度、行、方法、類

 

代碼覆蓋率的意義

Martin Fowler(重構那本書的作者)曾經寫過一篇博客來討論這個問題,他指出:把測試覆蓋作為質量目標沒有任何意義,而我們應該把它作為一種發現未被測試覆蓋的代碼的手段。

 

1、分析未覆蓋部分的代碼,從而反推在前期測試設計是否充分,沒有覆蓋到的代碼是否是測試設計的盲點,為什么沒有考慮到?需求/設計不夠清晰,測試設計的理解有誤,工程方法應用后的造成的策略性放棄等等,之后進行補充測試用例設計。

2、檢測出程序中的廢代碼,可以逆向反推在代碼設計中思維混亂點,提醒設計/開發人員理清代碼邏輯關系,提升代碼質量。
3、代碼覆蓋率高不能說明代碼質量高,但是反過來看,代碼覆蓋率低,代碼質量不會高到哪里去,可以作為測試自我審視的重要工具之一。

 

影響

1、進行完全的覆蓋性測試,提升設計能力; ---》對於測試
2、檢驗是否存在冗余代碼,理清邏輯思路; ---》對於開發

准備工作

下載jacoco,進入jacoco官網:http://www.eclemma.org/jacoco/ 

保證當前JDK在1.5以上

獲取到jacoco包jacoco-0.8.2.zip:

Windows下直接解壓,得到   D:\JAR\jacoco-0.8.2   目錄自定義即可

目錄結構圖如下:

Jacoco的lib目錄結構如下:

 

其中jacocoagent.jar是放置在Tomcat配置中作為代理同時啟動的jar包

 

對於jacocoant.jar是利用ant對覆蓋率進行處理的jar包

 

着重介紹和使用jacococli.jar,此包可直接在客戶端上執行,無需其他軟件。

 

 

Tomcat配置

 

 

1 關閉Tomcat, window是shutdown.bat擴展名、Linux是shutdown.sh擴展名

 

2 修改Windows下catalina.bat,在第二行添加如下腳本:

 

set JAVA_OPTS=-javaagent:D:\JAR\jacoco-0.8.2\lib\jacocoagent.jar=includes=*,output=tcpserver,port=9527,address=127.0.0.1,append=true -Xverify:none

 

   Linux修改catalina.sh,在第二行添加如下腳本:

 

JAVA_OPTS="-javaagent:/home/systemtools/jacoco-0.8.2/lib/jacocoagent.jar=includes=*,output=tcpserver,port=9527,address=192.168.43.100,append=true -Xverify:none"

  

 

JAVA_OPTS="-javaagent:[yourPath/]jacocoagent.jar=includes=com.companyName.*,output=tcpserver,port=PORT,address=IP -Xverify:none"
參數說明:
1. yourPath 是放 jacocoagent.jar 文件的目錄路徑;那么 `jacocoagent.jar` 這個 `jar` 包的路徑就是在准備工作里下載下來的 `zip` 包,解壓之后的 `lib` 目錄下。
2. includes 是指要收集哪些類(注意不要光寫包名,最后要寫.*),不寫的話默認是*,會收集應用服務上所有的類,包括服務器和其他中間件的類,一般要過濾(當然如果你願意寫*也完全沒有問題,如:`includes=com.*` or `includes=*`);
3. output 有 4 個值,分別是 file、tcpserver、tcpclient、mbean,默認是 file。使用 file 的方式只有在停掉應用服務的時候才能產生覆蓋率文件,而使用 tcpserver 的方式可以在不停止應用服務的情況下下載覆蓋率文件,后面會介紹如何使用 dump 方法來得到覆蓋率文件。
4. address 是 IP 地址,IP 就是 Tomcat 服務器的機器的 IP,至於是寫 `服務器本機的 IP` 還是寫 `127.0.0.1` 要看情況 1) 如果是在 Tomcat 服務器上執行 `ant dump` 的話,就直接寫 `address=127.0.0.1` 2) 如果執行 `ant dump` 不是在 Tomcat 服務器上執行的,就得寫服務器本機的IP(切記)
5. port 是端口(端口比較隨便,找個能用的端口就行,直接我為什么將端口寫成 `8044`,我的想法是 `BUG 死死` 與 `8044` 挺配的,所以就用它作為端口號了) (`address` 和 `port` 是使用 tcpserver 方式需要的 2 個參數,也是執行 ant dump 方法必須要用到的。)
6. `-Xverify:none`:這個參數是防止啟動主程序異常才加的(非強制,可以不加)

 

3 啟動Tomcat,Windows下使用startup.bat,Linux下使用startup.sh

 

4 驗證JAVA_OPTS是否有修改正確

 

     Windows下在cmd窗口使用WMIC命令,回車

 

        回顯:wmic:root\cli>

 

        在>后面輸入:process where name="java.exe"  命令

 

        查看回顯信息

 

 

注意:可能信息很長,而且在一行,需要拖動下方的滾動條查看

 

 

      Linux下載終端窗口中輸入ps -ef | grep tomcat

jacocoagent.jar的使用參數:

 

 

使用jacococli.jar包

 

 

使用釋疑

 

 

查看幫助,命令為:java -jar jacococli.jar --help

 

 

對於具體的command查看幫助信息。

 

命令如下:

 

java -jar jacococli.jar dump –help       # 獲取服務器端tcpserver模式輸出文件jacoco.exec

 

具體參數信息:

 

 

java -jar jacococli.jar instrument --help   # 離線java class文件和jar文件的指令集

 

 

java -jar jacococli.jar merge --help    #合並多個生成的.exec文件為一個新文件

java -jar jacococli.jar report --help     #通過讀取.exec和java的class文件生成不同文件格式的報告

java -jar jacococli.jar classinfo --help     # 在指定位置打印有關Java類文件的信息

 

java -jar jacococli.jar execinfo --help    # 以高可讀性打印exec文件信息

 

 

實例展示

 

 

以上面配置的Linux下Tomcat為例,使用命令:

java -jar jacococli.jar dump --address 192.168.43.100 --port 9527 --destfile ./jacoco.exec

 

引入Jenkins

 

 

配置

 

 

由於Jenkins提供了jacoco的插件,我們可以通過Jenkins來解析jacoco的exec文件

 

安裝jacoco插件,路徑:Jenkins > 系統管理 > 插件管理,在過濾框中輸入jacoco進行搜索

 

 

 

選中后,點擊【直接安裝】按鈕

 

安裝成功后可以在插件管理的已安裝標簽頁查看:

 

 

回到Jenkins首頁,點擊【新建任務】創建一個自由風格的job,名稱為:TestJacoco

 

在<配置>中,使用git獲取GitHub上的代碼================》圖略了。。。。。

 

 

在構建中,【增加構建步驟】,選擇<執行Windows批處理命令>(若Jenkins機器搭建在Linux下,可以選擇<執行shell>)

 

 

點擊左下角的【保存】按鈕。

 

執行<立即構建>

 

此時可以手動將jacococli.jar包放置到TestJacoco的工作目錄下。

 

目錄例如:

 

C:\Users\username\.jenkins\workspace\TestJacoco

將編譯好的.class 文件的文件夾,放置在jacococli.jar包的同一個目錄下。

此時,在<配置>中【增加構建后操作】選擇:<Record JaCoCo coverage report>

 

 

點擊【保存】

 

然后執行<立即構建>

 

可以在工程的目錄下查看到如圖所示信息:

 

 

點擊圖中區域任意位置,可以跳轉到如下:

 

 

可以通過圖中信息,查看所有代碼的覆蓋率信息。

 

針對其他的命令的使用,在這里不做逐一的解釋。有興趣可以按照參數列表進行探究。

 

 針對Springboot - 多module - 代碼覆蓋率統計

說明:web為啟動模塊,依賴關系:web->service->manager->dao->entity+common

新建了test模塊,當前模塊里什么代碼都沒有,但是POM中顯式依賴了其他所有模塊,顯式依賴就是為了聚合其他所有模塊的統計報告;

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mx.server.tsp</groupId>
    <artifactId>pom-management-test</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>pom-management-test</name>

    <parent>
        <groupId>com.mx.server.tsp</groupId>
        <artifactId>pom-management</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <dependencies>
        <!-- 依賴所有子模塊  -->
        <dependency>
            <groupId>com.mx.server.tsp</groupId>
            <artifactId>pom-management-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mx.server.tsp</groupId>
            <artifactId>pom-management-service</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mx.server.tsp</groupId>
            <artifactId>pom-management-manager</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mx.server.tsp</groupId>
            <artifactId>pom-management-dao</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mx.server.tsp</groupId>
            <artifactId>pom-management-entity</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mx.server.tsp</groupId>
            <artifactId>pom-management-common</artifactId>
        </dependency>
    </dependencies>
    
</project>

  

 

 注:test模塊是為了統一代碼覆蓋率報告而單獨建的模塊,且test->web+service+manager+dao+entity+common(test依賴其他所有子模塊)

 

綜上,為了合並多module的代碼測試覆蓋率統計報告,

(1)采用了JaCoCo插件,

(2)且單獨為了聚合統計報告而新建了一個test模塊,當前模塊沒有任何代碼,只是顯式依賴了其他所有子模塊,

(3)在項目根目錄下執行mvn install后,即可通過test模塊下的target/site/jacoco-aggregate/index.html查考到合並后的代碼測試覆蓋率報告;

 

針對具體的jacoco插件,進行數據分析。執行mvn test獲取結果。

 

            

    <!-- 單元覆蓋率插件-->
           <plugin>
              <groupId>org.jacoco</groupId>
              <artifactId>jacoco-maven-plugin</artifactId>
              <version>0.7.9</version>
              <executions>
                  <execution>
                  <id>pre-unit-test</id>
                  <goals>
                      <goal>prepare-agent</goal>
                  </goals>
                  <configuration>
                      <propertyName>jacocoArgLine</propertyName>
                  </configuration>
                  </execution>
                  <execution>
                  <id>post-unit-test</id>
                  <phase>package</phase>
                  <goals>
                      <goal>report</goal>
                  </goals>
                  </execution>
              </executions>
            </plugin>

<!---按照需要選擇插件數據---->

<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.7.201606060606</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>target/jacoco.exec</dataFile>
<outputDirectory>target/jacoco-out</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!------->

        <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-surefire-plugin</artifactId>                 <version>2.9</version>                 <configuration>                     <argLine>-Xmx256M ${jacocoArgLine}</argLine>                     <skip>false</skip>                     <testFailureIgnore>false</testFailureIgnore>                     <includes></includes>                     <excludes>                         <!-- 由於測試controller類需要啟動auth應用進行登錄請求,故剔除 -->                         <exclude>**/controller/*ControllerTest.java</exclude>                     </excludes>                 </configuration>             </plugin>

  

 

 

=======================END=========================


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM