文章目录
在测试过程中,为了解决 统计【行覆盖率】和【已经覆盖行数】两个指标,便于快速查看和复制,我们可以通过Jacoco去解决。
Jacoco是什么
Jacoco 是专门用于 Java 项目测试覆盖率检测的工具,由 EclEmma 项目演变而来。它能够精准地分析出代码中哪些部分已被测试覆盖,哪些部分尚未覆盖,为开发者优化测试用例提供了明确方向
Jacoco的主要功能
(一)多样化覆盖率指标分析
Jacoco 支持多种覆盖率指标,涵盖行覆盖、分支覆盖、方法覆盖和类覆盖等。行覆盖用于判断代码的每行是否至少有一个指令被执行;分支覆盖聚焦于如 if - else、switch 等语句分支的执行情况;方法覆盖判断方法是否被调用执行;类覆盖则确定类是否被执行。通过这些指标,开发者能全方位了解代码的测试覆盖状况。
(二) 丰富的报告生成
它能生成详细的覆盖率报告,且支持 HTML、XML 和 CSV 等多种格式。这些报告清晰展示代码的覆盖情况,突出显示未覆盖的代码区域,方便开发者分析和排查问题。
(三)实时数据收集
在测试运行时,Jacoco 可动态收集覆盖率数据,无需事后处理,能实时反映代码的测试状态,助力开发者迅速调整测试策略。
Jacoco的工作原理
(一)字节码增强
在测试运行前,Jacoco 会对 Java 字节码进行修改,插入覆盖率收集的逻辑,这一过程即 “字节码增强”。增强后的字节码包含用于记录代码路径执行情况的指令,为准确捕捉代码执行信息奠定基础。
(二)测试执行与数据收集
测试用例运行时,增强后的字节码会执行插入的覆盖率记录逻辑,实时收集代码行、分支、方法和类的执行信息。Jacoco 采用轻量级代理模式,对测试执行性能影响极小。测试完成后,Jacoco 汇总收集到的覆盖率数据,生成详细的覆盖率报告,清晰展示各代码单元的覆盖情况。
使用方法
需要工具
油猴插件:https://www.tampermonkey.net/
步骤
- 安装tampermonkey插件,并打开插件开关
- 点开详情,将允许访问文件网址打开,才可以生效与本地生成的jacoco覆盖率报告
- 通过管理面板,进入管理页面,新增脚本
- 通过添加新的脚本,将以下脚本键入并保存
// ==UserScript==
// @name 白盒覆盖率报告覆盖率插件
// @namespace http://tampermonkey.net/
// @version 0.1
// @description 用于jacoco报告的计算行覆盖率!
// @author lulu
// @match https://coverage.myshopline.cn/jacoco/report/*
// @match file:///*.html
// @icon https://www.google.com/s2/favicons?sz=64&domain=myshopline.cn
// @grant GM_addStyle
// @grant unsafeWindow
// @grant GM_setClipboard
// @require https://unpkg.com/jquery@3.6.0/dist/jquery.min.js
// @require https://unpkg.com/sweetalert2@10.16.6/dist/sweetalert2.all.min.js
// ==/UserScript==
(function() {
'use strict';
var element = document.querySelector("tbody");
var thead = document.querySelector('td#i');
var theadtdratio = document.createElement('td');
var coveredtd = document.createElement('td');
// 底部
var foot = document.querySelector('tfoot > tr > td:nth-of-type(9)');
var footcovered = document.createElement('td');
var footratiotd = document.createElement('td');
footcovered.setAttribute('class','ctr2')
footratiotd.setAttribute('class','ctr2')
foot.before(footcovered);
foot.after(footratiotd);
//设置表头
theadtdratio.innerHTML = '行覆盖率比例';
coveredtd.innerHTML = 'Covered';
thead.before(coveredtd);
thead.after(theadtdratio);
var coveredConut = 0;
// 获取地址
var url =window.location.href;
var baseUrl = url.substring(0,url.lastIndexOf('/')+1)
console.log('读取地址:',baseUrl)
for(var i=0; i<element.rows.length; i++){
var miss = parseInt(element.rows[i].cells[7].innerHTML.replace(/,/g, ""));
var lines = parseInt(element.rows[i].cells[8].innerHTML.replace(/,/g, ""));
var link = element.rows[i].cells[0].querySelector('a').getAttribute('href');
var covered = lines - miss
var result =Math.round((1- miss/lines) * 10000) / 100;
//添加结果
var td = document.createElement('td');
var alink = document.createElement('a');
alink.innerHTML = result +'%'
alink.href = baseUrl + link
td.appendChild(alink);
td.setAttribute('class','ctr2');
var coveredtd1 = document.createElement('td');
coveredtd1.innerHTML = covered;
coveredtd1.setAttribute('class','ctr2')
element.rows[i].cells[7].after(coveredtd1);
element.rows[i].cells[9].after(td);
coveredConut += covered;
//totalLines += result;
/*
//TODO 准备做一键复制
var copyButton = document.createElement('span');
copyButton.id = i;
copyButton.innerHTML = miss +'\n' + lines +'\n' + result
element.rows[i].appendChild(copyButton);
copyButton.onclick = function(miss){
//copy(miss+'\t'+lines+'\t'+result);
console.log('copy:'+copyButton.innerHTML);
//copy(parseInt(element.rows[i].cells[7].innerHTML.replace(/,/g, ""))+'\t'+parseInt(element.rows[i].cells[8].innerHTML.replace(/,/g, ""))+'\t'+td.innerHTML);
}
*/
//处于70-80
if(result>=75 && result < 100){
td.style.backgroundColor = '#00FFCC';
}
else if(result == 100){
td.style.backgroundColor = 'green';
}
//低于70%
else{
td.style.backgroundColor = 'red';
}
//总覆盖率
//totalLines += result;
console.log(miss,lines,link,result);
}
footcovered.innerHTML = coveredConut;
var tatolratiotd = coveredConut/parseInt(document.querySelector('tfoot > tr > td:nth-of-type(10)').innerHTML.replace(/,/g, "")) ;
footratiotd.innerHTML = Math.round(tatolratiotd * 10000) / 100 + '%';
if(tatolratiotd>=75 && tatolratiotd < 100){
footratiotd.style.backgroundColor = '#00FFCC';
}
else if(tatolratiotd == 100){
footratiotd.style.backgroundColor = 'green';
}
//低于70%
else{
footratiotd.style.backgroundColor = 'red';
}
const copy = (text) => {
GM_setClipboard(text, 'text');
}
})();
- 打开对应开关即可
本地启动开启Jacoco覆盖率
-
编辑运行配置
-
调整运行模板的junit code coverage配置为项目目录,并选择jacoco覆盖率统计工具
-
导出本地日志,保存后会自动打开报告可以查看