首页 > 其他分享 >JaCoCo增量覆盖率的基本实现原理

JaCoCo增量覆盖率的基本实现原理

时间:2022-11-28 12:04:52浏览次数:79  
标签:覆盖率 代码 JaCoCo class 增量 new jacoco

什么是增量覆盖率

JaCoCo增量覆盖率的基本实现原理_数据

如图所示,在master分支提交了HelloController,然后从master拉了个新分支test;提交了第1次代码,增加了WorldController;提交了第2次代码,增加了DonController。增量的获取方式有两种:

  • 版本对比:在分支上,第2次提交和第1次提交版本对比的增量代码,就是DonController;第2次提交和刚从master拉取分支时版本对比的增量代码,除了DonController还有WorldController;
  • 分支对比:把test分支和master分支进行对比,增量代码就是DonController和WorldController;

增量,就是通过版本对比或分支对比,多出来的新增加的那部分代码。覆盖率是指程序运行以后,有多少代码被执行到了,除以总的代码数算出来的,即​​覆盖率=执行代码行数/总代码行数​​​。增量覆盖率是针对增量代码来计算的,也就是​​增量覆盖率=执行代码行数/增量代码行数​​。

基本实现原理

JaCoCo增量覆盖率的基本实现原理_java_02

使用JaCoCo的On-the-fly模式,以tcpserver方式启动,将远程机器的覆盖率数据通过TCP通信dump到本地jacoco.exec文件,二次开发JaCoCo源码,实现增量覆盖率分析和输出HTML报告。

JaCoCo默认覆盖率

JaCoCo是一个开源的覆盖率工具,它的On-the-fly模式,无须侵入应用启动脚本,只需在JVM中通过-javaagent参数指定jar文件启动的代理程序,代理程序在ClassLoader装载一个class前判断是否需要注入class文件,将统计代码插入class,覆盖率分析就可以在JVM执行的过程中完成。

JaCoCo增量覆盖率的基本实现原理_html_03

启动脚本示例:

java -javaagent:jacocoagent.jar -jar target/app.jar

默认情况下,JaCoCo会在JVM停掉以后,生成覆盖率数据,一个jacoco.exec文件。

官方手册也有相关说明:

JaCoCo增量覆盖率的基本实现原理_java_04

output默认为file:At VM termination execution data is written to the file specified in the ​​destfile​​ attribute。这种方式有2个局限,一是必须停掉应用;二是只能把覆盖率数据生成到本地文件。

output还有另外一个选项,tcpserver

java -javaagent:jacocoagent.jar=output=tcpserver,address=0.0.0.0,port=2014 -jar target/app.jar

address:服务端地址;

port:服务端端口;

通过这种方式启动后,会同时启动一个TCP服务端,使用​​lsof -i :2014​​命令查看端口进程:

JaCoCo增量覆盖率的基本实现原理_java_05

然后就能通过TCP通信,来获取覆盖率数据,也就是所谓的”dump“。

代码片段:

@Override
public void dump(String dumpPath, String ip, int port) throws IOException {
dumpPath = FileUtil.getAbsolutePath(dumpPath);
if (!FileUtil.exist(dumpPath)) {
FileUtil.mkdir(dumpPath);
}
FileOutputStream localFile = new FileOutputStream(dumpPath + File.separator + "jacoco.exec");
ExecutionDataWriter localWriter = new ExecutionDataWriter(localFile);
SocketAddress socketAddress = new InetSocketAddress(ip, port);
Socket socket = new Socket();
try {
socket.connect(socketAddress, 10000);
RemoteControlWriter writer = new RemoteControlWriter(socket.getOutputStream());
RemoteControlReader reader = new RemoteControlReader(socket.getInputStream());
reader.setSessionInfoVisitor(localWriter);
reader.setExecutionDataVisitor(localWriter);
log.info("开始dump:{} {}", ip, port);
writer.visitDumpCommand(true, false);
if (!reader.read()) {
log.error("Socket closed unexpectedly");
throw new IOException("Socket closed unexpectedly.");
}
log.info("dump完成:{} {}", ip, port);
} catch (Exception e) {
log.info("dump失败:{}", e.getMessage());
} finally {
socket.close();
localFile.close();
}
}

dump经过TCP通信,将远程机器的覆盖率数据取到本地后,生成jacoco.exec文件,然后可以使用jacococli.jar生成HTML报告:

java -jar jacococli.jar report ./dump/jacoco.exec --classfiles ./target/classes/ --sourcefiles ./src/main/java/ --html ./report

第1个参数:jacoco.exec文件路径;

第2个参数:class文件路径;

第3个参数:src源码路径;

第4个参数:报告存放地址;

JaCoCo也提供了OpenApi来生成报告。

代码片段:

dumpPath = FileUtil.getAbsolutePath(dumpPath);
classFilesPath = FileUtil.getAbsolutePath(classFilesPath);
srcPath = FileUtil.getAbsolutePath(srcPath);
reportPath = FileUtil.getAbsolutePath(reportPath);

File execFile = new File(dumpPath + File.separator + "jacoco.exec");
ExecFileLoader execFileLoader = new ExecFileLoader();
execFileLoader.load(execFile);

CoverageBuilder coverageBuilder = new CoverageBuilder();

Analyzer analyzer = new Analyzer(execFileLoader.getExecutionDataStore(), coverageBuilder);
analyzer.analyzeAll(new File(classFilesPath));
String reportTile = "报告标题";
IBundleCoverage bundleCoverage = coverageBuilder.getBundle(reportTile);
HTMLFormatter htmlFormatter = new HTMLFormatter();
IReportVisitor iReportVisitor = htmlFormatter.createVisitor(new FileMultiReportOutput(new File(reportPath)));
iReportVisitor.visitInfo(execFileLoader.getSessionInfoStore().getInfos(), execFileLoader.getExecutionDataStore().getContents());
DirectorySourceFileLocator directorySourceFileLocator = new DirectorySourceFileLocator(new File(srcPath), "utf-8", 4);
iReportVisitor.visitBundle(bundleCoverage, directorySourceFileLocator);
iReportVisitor.visitEnd();

JaCoCo的org.jacoco.core和org.jacoco.report两个包提供了这些方法。

JaCoCo默认只能分析全量覆盖率。

改造JaCoCo支持增量

改造的底层逻辑是,在分析覆盖率数据时,class文件只选取git diff的文件,从而只统计差异的增量代码,实现增量覆盖率。

在ClassProbesAdapter类的​​visitMethod​​方法里面,有一个对方法级别的探针计算逻辑,改造它,只对提取出的每个类的新增或变更方法做解析。

代码片段:

JaCoCo增量覆盖率的基本实现原理_html_06

JaCoCo增量覆盖率的基本实现原理_数据_07

CoverageBuilder.classInfos是git diff出来的差异类。

改造CoverageBuilder支持分支对比和版本对比:

JaCoCo增量覆盖率的基本实现原理_数据_08

获取差异代码使用jgit和jdt切割到了方法粒度:

JaCoCo增量覆盖率的基本实现原理_数据_09

完整源码可以参考开源项目JacocoPlus:

​https://github.com/512433465/JacocoPlus​

关键点

JaCoCo分析覆盖率有时候结果不准确,通常跟这两个关键点有关:

一是dump,dump的频次很重要,建议每次分析时都dump一次,保证覆盖率数据是最新的。分布式集群会有多份覆盖率数据,可以使用ExecFileLoader的load和save方法将多份数据合并为一份。应用重启会丢失覆盖率数据,可以做一些备份。

二是class,在生成报告时,会将class和src进行比对,以统计覆盖率,只有当class和src完全匹配才能得到准确的覆盖率,假如我们自己拉最新的代码进行编译得到class,由于编译环境和版本的影响,编译出来的class说不定跟src就不匹配了,统计结果也就不会准确。最好是从应用上拉取部署的class来进行对比,以保证class和src的完全匹配。

JaCoCo - Java Agent ​​https://www.jacoco.org/jacoco/trunk/doc/agent.html​

JaCoCo - API Usage Examples ​​https://www.jacoco.org/jacoco/trunk/doc/api.html​

增量代码覆盖率工具 ​​https://tech.youzan.com/yzicov/​

有赞精准测试实践 ​​https://tech.youzan.com/thanos/​

Java覆盖率Jacoco插桩的不同形式总结和踩坑记录 ​​https://testerhome.com/topics/20632​

jacoco 代码覆盖率使用中遇到的一些坑 ​​https://testerhome.com/topics/16925​

jacoco—增量代码覆盖率实现

公众号【测试开发刚哥】

版权申明:本文为博主原创文章,转载请保留原文链接及作者。



标签:覆盖率,代码,JaCoCo,class,增量,new,jacoco
From: https://blog.51cto.com/u_15186953/5890819

相关文章

  • 【Kettle】kettle | 数据表增量脚本 | 表输入变量
    一、说明        1、数据库,MySQL        2、根据ID备份增量数据        3、主键为bigint,且自增        4、增量策略,根据ID判断增量   ......
  • JaCoCo增量覆盖率的基本实现原理
    什么是增量覆盖率如图所示,在master分支提交了HelloController,然后从master拉了个新分支test;提交了第1次代码,增加了WorldController;提交了第2次代码,增加了DonController。......
  • 07.电商终极搜索的深入优化使用(1) es增量同步,es案例
                                         ......
  • 增量型PID公式
    Uk=Uk+KP*【E(k)-E(k-1)】+KI*E(k)+KD*【E(k)-2E(k-1)+E(k-2)】Uk:输出值;E(k):当前误差值;E(k-1):上次误差值;KP:比例系数;KI:微分系数;KD:积分系数;E(k)= Uk-......
  • rsync+inotify 实现资源服务器间增量备份
    测试环境:资源服务器(主服务器):192.168.4.163备份服务器(客户端):192.168.4.154同步资源目录:/etc/test实验目的:资源服务器的同步目录下的文件变化时,备份服务器的同步目录更新,以资......
  • 【增量中继】基于增量中继与机会中继的协同通信的matlab仿真
    1.软件版本matlab2013b2.系统描述在近年来提出的协同通信方案中,机会中继(OR,OpportunisticRelaying)是比较合理和可行的一种方案。它是一种分布式的单中继方案,其独特之......
  • Xmake v2.7.3 发布,包组件和 C++ 模块增量构建支持
    Xmake是一个基于Lua的轻量级跨平台构建工具。它非常的轻量,没有任何依赖,因为它内置了Lua运行时。它使用xmake.lua维护项目构建,相比makefile/CMakeLists.txt,配置语......
  • JAVA代码覆盖率工具JaCoCo
    一、代码覆盖率统计工具的能与不能能:代码覆盖率统计工具能用来发现没有被测试(单元测试、接口自动化测试、ui自动化测试、手工测试等)覆盖的代码。1、测试中未覆盖的代码......
  • 【随机过程】随机过系列之特征函数、宽平稳与平稳独立增量
    1.特征函数随机过程常见表示方式:${X(t);t\inT}$,有四个特征函数,见下表。特征函数表达式理解均值函数$\mu_X(t)=E[X(t)]$相当于随机变量的均值,知当t确定......
  • kettle如何实现增量更新
    当在实际项目过程中我们需要对数据进行增量更新操作举个例子一张生活轨迹融合表是有上网信息和入住酒店信息两张表的数据unionall产生,如果一个融合表是多张表融合的,......