通過JaCoCo統計接口測試代碼覆蓋率


通過JaCoCo統計接口測試代碼覆蓋率

需求:統計微服務接口測試的代碼覆蓋率

  1. JaCoCo的ant與maven方法都是在編譯期對單元測試的覆蓋率統計
  2. JaCoCo的可以開啟一個agent服務收集運行過程中的代碼執行覆蓋率。
    主要會用到jacoco 的兩個功能:agent和cli

覆蓋率收集

1. 收集方式

鑒於接口測試是在微服務啟動后運行的測試,所以在選用第二種agent的測試,會有兩個比較麻煩的地方(列出了自己比較笨拙的解決方法)

  1. 源碼獲取:去git上再拉取一遍。
  2. 編譯后字節碼獲取:按照測試環境構建再統計過程中再構建一遍。

統計覆蓋率過程基本如:

  1. 微服務啟動,同時啟動agent收集覆蓋率
  2. 接下來基本都是jenkins任務需要做的
  • git獲取項目源碼
  • 使用構建工具編譯源碼
  • 使用cli工具獲取JaCoCo覆蓋率統計文件
  • 使用cli工具根據exec文件生成覆蓋率報告

2. JaCoCo使用

參考jacoco官方使用文檔:官方文檔索引agent幫助文檔cli幫助文檔

  • JaCoCo官方給出了3種收集覆蓋率文件的方式:file、tcpserver、tcpclient。

在JVM虛擬機啟動時加入參數: -javaagent:[yourpath/]jacocoagent.jar=[option1]=[value1],[option2]=[value2] , 實例如下:

# Example: 輸出到文件,在JVM終止時,執行數據被寫入本地文件。接口測試不會考慮這種情況(單測一般是用這種)
# 1. 服務終止影響整個測試環境。
# 2. 有些跨環境的服務,獲取微服務所在機器上的文件也比較麻煩。
-javaagent:~/jacoco-0.8.5/lib/jacocoagent.jar=includes=*,output=file,append=true,destfile=~/jacoco-0.8.5/jacoco.exec
 # Example: 輸出到tcpserver,使用工具連接到JVM,獲取dump數據。使用這種方式不需要停止jvm,也直接可以通過網絡傳輸。但是遠程連接沒有任何身份驗證機制,所以生產環境一定要確保只有信任的人可訪問jacoco地址。配合jacoco cli獲取數據。
-javaagent:~/jacoco-0.8.5/lib/jacocoagent.jar=includes=*,output=tcpserver,append=true,address=127.0.0.1,port=6301
 # 列出部分參數,
# includes:插樁的代碼類名列表,使用:分割,也可以使用*和?匹配,但是不考慮性能的情況下一般不需要使用。默認為*
# output:用於寫入coverage數據的輸出方法。有效選項包括:file、tcpserver、tcpclient、none
# append:如果文件已經存在則追加到已存在文件中,如果為false則替換
# destfile:輸出exec文件的路徑
# address:配合tcpserver來指定對外開放的jacoco訪問地址。如果配置的127.0.0.1或localhost則只能本地訪問dump數據
# port:配合tcpserver來指定對外開放的jacoco端口。端口不能被占用
  • JaCoCo命令行界面:命令行界面提供了基本的操作,基本能滿足接口覆蓋率報告的生成;dump數據與生成報告都使用cli。
# Example:獲取jacoco server對外開放地址的數據。
# --address jacoco tcpserver地址,網絡要通不然啥都白搭。
# --port jacoco tcpserver端口
# --destfile dump數據存儲位置
java -jar ${jacoco_home}/lib/jacococli.jar dump --address ${address} --port ${port} --destfile ${destfile}
 # Example:使用獲取到的exec文件生成覆蓋率報告。
# --classfiles 必須指定,源碼編譯后target目錄文件。(這也是jenkins任務在單獨拉取源碼執行編譯的原因)
# --sourcefiles 源碼,非必須項。不指定無法查看代碼執行詳細情況。
# --html html報告生成目錄
java -jar ${jacoco_home}/lib/jacococli.jar report ${destfile} --classfiles ${classfiles} --sourcefiles ${sourcefiles} --html reportdir

接下來創建一個項目實驗一下

Sprint Boot測試項目

1. 創建項目

創建Spring boot項目
創建Spring boot項目

項目信息
項目信息

Sprint Web
Sprint Web

2. 工程結構

src
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           └── demo/
│   │               ├── JacocoDemoApplication.java
│   │               └── controller/
│   │                   └── CountController.java 測試controller
│   └── resources/
│       ├── application.properties
│       ├── static/
│       └── templates/
└── test/
    └── java/
        └── com/
            └── example/
                └── demo/
                    └── JacocoDemoApplicationTests.java

3. CountController.java

package com.example.demo.controller;

import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
public class CountController {

    @RequestMapping(value = "/test1", method = RequestMethod.POST)
    @ResponseBody
    public boolean caseCount(@RequestBody Map<String, Integer> params) {
        if (params.get("count") > 0) {
            return true;
        } else {
            return false;
        }
    }

    @RequestMapping(value = "/test2", method = RequestMethod.POST)
    @ResponseBody
    public boolean caseCount1(@RequestBody Map<String, Integer> params) {
        if (params.get("count") > 0) {
            return true;
        } else {
            return false;
        }
    }
}

4. 上傳代碼到github

創建項目
創建項目

倉庫地址
倉庫地址

# 進入項目目錄,初始化項目
git init
# 新增修改文件。
git add .
# 按照上一步提示使用命令設置本項目的賬戶(也可以加--global設置全局)
git config --local user.email '***'
# 提交本次新增內容
git commit -m 'jacoco 代理統計覆蓋率demo代碼'
# 設置代碼庫地址
git remote add origin https://github.com/hzhang123/jacoco-demo.git
# 獲取項目初始化的README.md文件
git pull --rebase origin master
# 上傳到github。 可能會讓輸入用戶名密碼
git push -u origin master

覆蓋率統計測試

我這里全部是本地項目,所以都用的本地127.0.0.1

1. 啟動項目

  • 添加參數啟動項目

JVM啟動參數加入tcpserver啟動收集方式的參數
JVM啟動參數加入tcpserver啟動收集方式的參數

  • postman 發送測試請求

test1接口fasle分支
test1接口fasle分支

test2接口true分支
test2接口true分支

2. jenkins任務

  • 添加流水線任務

JacocoDemo
JacocoDemo

  • 添加string參數

string 構建參數
string 構建參數

  • Pipeline script

只是測試,所以pipeline腳本中有有一些參數我直接寫死了,比如:GIT_BRANCH、CODE_REPO、jacoco_home、classfiles、sourcefiles,可以根據不同項目配置一下構建參數。

#!/usr/bin/env groovy

pipeline {
    agent any

    environment {
        // 如果scala構建使用sbt,jenkins兼容不太好需要environment中拼接工具地址
        SBT_HOME = tool name: 'sbt1.3.0', type: 'org.jvnet.hudson.plugins.SbtPluginBuilder$SbtInstallation'
        PATH = "${env.SBT_HOME}/bin:${env.PATH}"
        // 可以添加構建參數用來指定獲取分支等信息
        GIT_BRANCH = "master"
        CODE_REPO = "https://github.com/hzhang123/jacoco-demo.git"
    }
    tools {
        // 引入tools中配置的工具
        maven "maven3.6.1"
        jdk 'jdk1.8.0_231'
    }
    stages {
        stage('Clone & Build') {
            steps {
                deleteDir()
                git branch: env.GIT_BRANCH, url: CODE_REPO
                // 如果有Phabricator & Arcanist工具可以配合review與打patch
                // script {
                // diffs = DIFFS.trim().toUpperCase().split("(\\s+|\\s*,\\s*)")
                // for (i = 0; i < diffs.length; i++) {
                // id = diffs[i];
                // if (id.trim().length() > 0) {
                // sh "arc patch ${id}"
                // sh "git checkout ${GIT_BRANCH}"
                // sh "git merge arcpatch-${id}"
                // }
                // }
                // }
                sh "mvn clean package"
            }
        }
        stage('Exec & Report') {
            steps {
                sh ''' # JaCoCo依賴在jenkins上的地址 jacoco_home="/Users/growingio/developments/tools/jacoco-0.8.5" # ---------------- # dump tcp端口數據 # ---------------- address=`echo ${server_addr} | awk -F: '{print $1}'` port=`echo ${server_addr} | awk -F: '{print $2}'` destfile=target/JacocoDemo.exec java -jar ${jacoco_home}/lib/jacococli.jar dump --address ${address} --port ${port} --destfile ${destfile} # 生成報告 classfiles="target/classes" sourcefiles="src/main/java" java -jar ${jacoco_home}/lib/jacococli.jar report ${destfile} --classfiles ${classfiles} --sourcefiles ${sourcefiles} --html report '''
            }
        }
        stage('publishHTML & Clean Workspace') {
            steps {
                publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: false, reportDir: "report", reportFiles: 'index.html', reportName: 'HTML Report', reportTitles: ''])
                cleanWs()
            }
        }
    }
}

3. 構建報告

詳細參數可以查看官方文檔:代碼覆蓋率參數文檔

Instructions (C0 Coverage):JaCoCo 計算的最小單位就是字節碼指令。指令覆蓋率表明了在所有的指令中指令執行的覆蓋率。
Branches (C1 Coverage):JaCoCo還計算所有的for與if分支覆蓋率,異常處理不在分支計算范圍內。黃色(部分覆蓋)、紅色(未覆蓋)、綠色(全部覆蓋)
Cyclomatic Complexity:圈復雜度
Line:可能一行會被編譯為多個指令,所以在源碼高亮顯示每行代碼的情況。黃色(部分覆蓋)、紅色(未覆蓋)、綠色(全部覆蓋)
Methods:每個方法至少包含一個指令,當改指令被執行時認為方法被執行。
Classes:每個類至少包含一個方法,當該方法被執行時認為類被執行。

報告概覽
報告概覽

代碼詳細執行情況
代碼詳細執行情況


免責聲明!

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



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