文章目录

概要

所有代码已经上传到gitee,仓库地址:https://gitee.com/chen_zai_xing/jacoco。最新版本支持自定义数据结构,如请求者IP,以IP划分探针数据,此版本暂时不考虑开源,需付费支持。
方法指令合并参考ray大佬的https://blog.csdn.net/tushuping/article/details/131640959?spm=1001.2014.3001.5502,大佬在文中未提及指令签名带上指令相对于方法中的序号,这里补充说明下。(序号是为了区分操作码和值一样的指令)。
在这里插入图片描述

上述方案解决了方法级别报告覆盖率合并的问题,但是不能完美解决不同时间点合并多个版本覆盖率。比如A->B->C测试节点,A->C是个完整节点,但是有些测试是在B节点完成的,整个测试流程不能直接合并A和C的覆盖率,需要同时合并A->B->C的覆盖率,这也是本文主要解决的问题。
官方提供的merge方法只能支持合并同个class内容的exec数据,只要class内容变更,那么根据class字节流计算出来的classId势必不同,所以无法满足使用场景:一个版本测试周期内,开发多次修改class并部署测试环境,生成覆盖率报告后不能展示完整的测试覆盖率。
借用下ray佬的图
在合并完成后的覆盖率
基于上述的场景需要改造jacoco以支持合并不同的class覆盖率,实现同一个全类名的类,方法没有变更的覆盖率合并到新的同一个全类名的覆盖率。改造合并的逻辑是合并探针的数据,在report.java增加一个参数控制是否生成报告还是生成exec文件,在多个版本合并的时候每次合并的时候选择生成exec文件,这样就解决A->B->C的问题,先合并AB,把A的方法未变更的覆盖率合并到B,产生新的exec文件,然后使用新的exec文件再次和C的进行合并,得到最终的exec文件,根据最终的exec文件再生成最终的覆盖率报告。
现在需要解决的问题就是怎么才能合并同个方法探针的数据。具体方法在Instruction类增加一个probeIndex变量,在report调用MethodAnalyzer的时候记录方法指令的探针probeId,probeId是probes中的探针的顺序,如果我们可以知道方法中的指令对应的探针probeId,那么在合并方法指令的时候就可以同时更新探针的数据。jacoco插桩时候的探针顺序是ClassProbesAdapter中的counter控制的,也就是说我们只需要拿到这个counter的值就可以知道当前的探针顺序。在IProbeIdGenerator接口类增加一个getId方法,返回当前的probeId.
在IProbeIdGenerator接口类增加一个getId方法
ClassProbesAdapter中实现getId方法,返回当前的probeId
在调用MethodAnalyzer的时候去获取当前的探针probeId,builder.addInstruction(currentNode, sign, currentProbeId)传入当前的探针顺序,这样子就可以记录方法中指令的探针probeId了,在后面进行方法的指令合并时候,同时合并探针。
在这里插入图片描述
增加参数是否只合并exec文件,生成exec文件
现在已经解决了指令和探针关联起来了的问题,如果可以知道每个方法对应的探针数组索引,那么就可以直接合并exec中的探针数据了。
比如A.class存在方法test(),exec1对应的探针索引是[5-15],A.class(V2),exec2对应的test()方法没有改变,改变的是其他的方法内容,对应的探针索引是[15-25],方法内容没有修改所以探针长度不会发生变化。
此时,exec2对应的探针索引直接和exec1对应的探针索引进行合并,合并时取其中为真的探针索引。
在analy class的时候,使用ThreadLocal<Map<String, Map<String, Map<String, Instruction>>>> instrunctionsThreadLocal。记录每个方法关联的指令集合,在合并的时候通过指标集合是否完全一致来判断是否是一个方法。指令是否一样通过操作码,操作值,和指令在ASM遍历methodNode.instructions的索引是否一样来判断。
如有任何疑问可以加微信群交流下,备注效能交流,已建立效能交流

在这里插入图片描述

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐