Jacoco增量覆盖率说明
能找到这里,说明对jacoco的原理和使用有了一定的了解,而我写这边文章主要是网络上基本没有完整文档加代码的jaocco增量覆盖说明,所以我想分享些东西让需要这方面的人快速去实现自己想要的功能,那么如果想实现增量代码覆盖率需要做到哪些工作呢?
大家在网络上找到的实现方式无外乎三种
- 获取到增量代码,在jacoco进行插桩时判断是否是增量代码后再进行插桩,这样需要两个步骤,一是获取增量代码,二是找到jacoco的插桩逻辑进行修改
- 获取增量代码,在report阶段去判断方法是否是增量,再去生成报告
- 获取差异代码,解析生成的report报告,再过滤出差异代码的报告
首先第一种需要对java字节码操作比较熟悉,难度较高,我们不谈,第三种去解析生成的报告,可能存在误差
所以我们一般选择第二种,而网络上所有的增量实现基本是基于第二种,我们先看看下面的图

上图说明了jacoco测试覆盖率的生成流程,而我们要做的是在report的时候加入我们的逻辑
根据我们的方案,我们需要三个动作
- 计算出两个版本的差异代码(基于git)
- 将差异代码在jacoco的report阶段传给jacoco
- 修改jacoco源码,生成报告时判断代码是否是增量代码,只有增量代码才去生成报告
下面我们逐步讲解上述步骤
计算差异代码
计算差异代码我实现了一个简单的工程:差异代码获取
主要用到了两个工具类
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.javaparser/javaparser-core -->
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
</dependency>
org.eclipse.jgit主要用于从git获取代码,并获取到存在变更的文件
javaparser-core是一个java解析类,能将class类文件解析成树状,方便我们去获取差异类
/**
* 获取差异类
*
* @param diffMethodParams
* @return
*/
public List<ClassInfoResult> diffMethods(DiffMethodParams diffMethodParams) {
try {
//原有代码git对象
Git baseGit = cloneRepository(diffMethodParams.getGitUrl(), localBaseRepoDir + diffMethodParams.getBaseVersion(), diffMethodParams.getBaseVersion());
//现有代码git对象
Git nowGit = cloneRepository(diffMethodParams.getGitUrl(), localBaseRepoDir + diffMethodParams.getNowVersion(), diffMethodParams.getNowVersion());
AbstractTreeIterator baseTree = prepareTreeParser(baseGit.getRepository(), diffMethodParams.getBaseVersion());
AbstractTreeIterator nowTree = prepareTreeParser(nowGit.getRepository(), diffMethodParams.getNowVersion());
//获取两个版本之间的差异代码
List<DiffEntry> diff = nowGit.diff().setOldTree(baseTree).setNewTree(nowTree).setShowNameAndStatusOnly(true).call();
//过滤出有效的差异代码
Collection<DiffEntry> validDiffList = diff.stream()
//只计算java文件
.filter(e -> e.getNewPath().endsWith(".java"))
//排除测试文件
.filter(e -> e.getNewPath().contains("src/main/java"))
//只计算新增和变更文件
.filter(e -> DiffEntry.ChangeType.ADD.equals(e.getChangeType()) || DiffEntry.ChangeType.MODIFY.equals(e.getChangeType()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(validDiffList)) {
return null;
}
/**
* 多线程获取旧代码和新代码的差异类及差异方法
*/
List<CompletableFuture<ClassInfoResult>> priceFuture = validDiffList.stream().map(item -> getClassMethods(getClassFile(baseGit, item.getNewPath()), getClassFile(nowGit, item.getNewPath()), item)).collect(Collectors.toList());
return priceFuture.stream().map(CompletableFuture::join).filter(Objects::nonNull).collect(Collectors.toList());
} catch (GitAPIException e) {
e.printStackTrace();
}
return null;
}
以上代码为获取差异类的核心代码
/**
* 获取类的增量方法
*
* @param oldClassFile 旧类的本地地址
* @param mewClassFile 新类的本地地址
* @param diffEntry 差异类
* @return
*/
private CompletableFuture<ClassInfoResult> getClassMethods(String oldClassFile, String mewClassFile, DiffEntry diffEntry) {
//多线程获取差异方法,此处只要考虑增量代码太多的情况下,每个类都需要遍历所有方法,采用多线程方式加快速度
return CompletableFuture.supplyAsync(() -> {
String className = diffEntry.getNewPath().split("\\.")[0].split("src/main/java/")[1];
//新增类直接标记,不用计算方法
if (DiffEntry.ChangeType.A

本文详细介绍了如何通过jacoco实现增量代码覆盖率,包括差异代码的获取、jacoco插桩逻辑的修改以及report阶段的判断,提供了完整的代码示例和解决参数匹配问题的方法。
最低0.47元/天 解锁文章
2087

被折叠的 条评论
为什么被折叠?



