深圳龙华汽车网站建设,活动策划怎么写,建设网站需要具备什么条件,自己做单词卡的网站是什么在开发精准测试覆盖率相关的功能时候#xff0c;对于Android的增量报告#xff0c;由于担心修改jacoco插件会影响App的打包#xff0c;所以一直没有修改。在网上查了一下#xff0c;没有找到合适的方案。只有一个diff-cover开源项目#xff1a;https://github.com/abmaonl… 在开发精准测试覆盖率相关的功能时候对于Android的增量报告由于担心修改jacoco插件会影响App的打包所以一直没有修改。在网上查了一下没有找到合适的方案。只有一个diff-cover开源项目https://github.com/abmaonline/diff-cover 经过测试可以生成对比分支的增量报告可是对于对比版本就不太适应了。于是就各种调研最后通过最低层的方案过滤文件和函数于是有了第一个版本的增量覆盖率报告生成方案。
一增量覆盖率报告方案一
第一版本的增量覆盖率报告如下流程 此方案虽然能生成增量覆盖率报告但存在如下问题
1diff-cover生成的报告只能对比分支不能对比版本并且生成的覆盖率报告和jacoco相差很大
2生成的报告数据欠缺diff-cover只有行覆盖率而对比版本过滤的方案生成的有行方法和类但没有分支数据
3操作比较繁琐要过滤很多数据如果diff文件较多生成时间比较长
4最终的代码渲染没有办法按增量处理只能过滤出diff类对应的文件渲染则是全量的。 二增量覆盖率报告方案二 Android jacoco生成增量报告早期没有找到合适的方案后面做了一些调研发现下面有个方案
1参考文档
Android 增量代码测试覆盖率工具实践https://juejin.cn/post/6920029313316159502
2开源项目
AndJacocohttps://github.com/ttpai/AndJacoco 此方案的核心思想是 通过指定的对比方式或是分支或是版本找到diff的文件及函数列表 在jacoco进行注入的时候只对增量代码做注入 最后根据采集的覆盖率数据生成报告即为增量报告。
经过各种尝试发现这个项目在文件org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java 中与jacoco github上的有差别https://github.com/jacoco/jacoco/blob/master/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java
主要是下面这个函数修改成与github上的一样就可以可能是这个jacoco项目比较早的原因
private static int getFirstGeneratedLineNumber(final String sourceFileName,final String smap) {try {final BufferedReader br new BufferedReader(new StringReader(smap));expectLine(br, SMAP);// OutputFileNameexpectLine(br, sourceFileName);// DefaultStratumIdexpectLine(br, Kotlin);// StratumSectionexpectLine(br, *S Kotlin);// FileSectionexpectLine(br, *F);final BitSet sourceFileIds new BitSet();String line;while (!*L.equals(line br.readLine())) {// AbsoluteFileNamebr.readLine();final Matcher m FILE_INFO_PATTERN.matcher(line);if (!m.matches()) {throw new IllegalStateException(Unexpected SMAP line: line);}final String fileName m.group(2);if (fileName.equals(sourceFileName)) {sourceFileIds.set(Integer.parseInt(m.group(1)));}}if (sourceFileIds.isEmpty()) {throw new IllegalStateException(Unexpected SMAP FileSection);}// LineSectionint min Integer.MAX_VALUE;while (true) {line br.readLine();if (line.equals(*E) || line.equals(*S KotlinDebug)) {break;}final Matcher m LINE_INFO_PATTERN.matcher(line);if (!m.matches()) {throw new IllegalStateException(Unexpected SMAP line: line);}final int inputStartLine Integer.parseInt(m.group(1));final int lineFileID Integer.parseInt(m.group(2).substring(1));final int outputStartLine Integer.parseInt(m.group(4));if (sourceFileIds.get(lineFileID) inputStartLine outputStartLine) {continue;}min Math.min(outputStartLine, min);}return min;} catch (final IOException e) {// Must not happen with StringReaderthrow new AssertionError(e);}
}
开源项目的函数检测也有问题需要改成如下所示 CodeDiffUtil.java
/******************************************************************************** Copyright (c) 2009, 2021 Mountainminds GmbH Co. KG and Contributors* This program and the accompanying materials are made available under* the terms of the Eclipse Public License 2.0 which is available at* http://www.eclipse.org/legal/epl-2.0** SPDX-License-Identifier: EPL-2.0** Contributors:* Marc R. Hoffmann - initial API and implementation********************************************************************************/
package org.jacoco.core.internal.diff;import org.jacoco.core.analysis.CoverageBuilder;
import org.objectweb.asm.Type;import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;/*** ProjectName: root* Package: org.jacoco.core.internal.diff* Description: 差异代码处理类* Author: duanrui* CreateDate: 2021/1/12 15:17* Version: 1.0* p* Copyright: Copyright (c) 2021*/
public class CodeDiffUtil {private final static String OPERATE_ADD ADD;private static String OutputStream;/*** 检测类是否在差异代码中** param className* return Boolean*/public static Boolean checkClassIn(String className,ListClassInfoDto classInfos) {if (null classInfos || classInfos.isEmpty() || null className) {return Boolean.FALSE;}System.out.println(classNameclassName)// 这里要考虑匿名内部类的问题return classInfos.stream().anyMatch(c - className.equals(c.getClassFile())|| className.split(\\$)[0].equals(c.getClassFile()));}/*** 检测方法是否在差异代码中** param className* param methodName* return Boolean*/public static Boolean checkMethodIn(String className, String methodName,String desc, ListClassInfoDto classInfos) {// 参数校验if (null classInfos || classInfos.isEmpty() || null methodName|| null className) {return Boolean.FALSE;}ClassInfoDto classInfoDto classInfos.stream().filter(c - className.equals(c.getClassFile())|| className.split(\\$)[0].equals(c.getClassFile())).findFirst().orElse(null);if (null classInfoDto) {return Boolean.FALSE;}// 如果是新增类不用匹配方法直接运行if (OPERATE_ADD.equals(classInfoDto.getType())) {return Boolean.TRUE;}if (null classInfoDto.getMethodInfos()|| classInfoDto.getMethodInfos().isEmpty()) {return Boolean.FALSE;}// 匹配了方法参数也需要校验return classInfoDto.getMethodInfos().stream().anyMatch(m - {if (methodName.equals(m.getMethodName())) {// System.out.println(className className ,methodName// methodName ,parmas desc ,m.getParameters()// m.getParameters().toString());return checkParamsIn(m.getParameters(), desc);// lambda表示式匹配} else if (methodName.contains(lambda$) methodName.split(\\$)[1].equals(m.getMethodName())) {return Boolean.TRUE;} else {return Boolean.FALSE;}});}/*** 匹配参数* param params* 格式String a* param desc* 转换后格式 java.lang.String* return*/public static Boolean checkParamsIn(ListString params, String desc) {// 解析ASM获取的参数Type[] argumentTypes Type.getArgumentTypes(desc);// 处理一下params,直接使用list有问题String ckparams ;if (params.size() 1) {ckparams params.get(0);ckparams ckparams.trim();if (ckparams.length() 0 argumentTypes.length 0) {return Boolean.TRUE;} else {String[] diffParams ckparams.split(,);// 只有参数数量完全相等才做下一次比较Type格式I C Ljava/lang/String;if (diffParams.length 0 argumentTypes.length diffParams.length) {for (int i 0; i argumentTypes.length; i) {// 去掉包名只保留最后一位匹配,getClassName格式 int java/lang/StringString[] args argumentTypes[i].getClassName().split(\\.);String arg args[args.length - 1];// 如果参数是内部类类型再截取下if (arg.contains($)) {arg arg.split(\\$)[arg.split(\\$).length - 1];}if (!diffParams[i].toLowerCase().contains(arg.toLowerCase())) {return Boolean.FALSE;}}// 只有个数和类型全匹配到才算匹配return Boolean.TRUE;}return Boolean.FALSE;}} else {return Boolean.FALSE;}}
}
3构建项目 从https://gitee.com/Dray/jacoco下载项目修改KotlinInlineFilter.java 文件如上面所示执行打包命令
mvn clean install -Dmaven.test.skiptrue -Dmaven.javadoc.skiptrue
项目会下载很多依赖的包耐心等待即可。最后命令执行完成后发现出错了如下所示 相应的jar包打包完成没有问题。
4测试修改后的包 看项目的介绍需要使用org.jacoco.cli-0.8.7-SNAPSHOT-nodeps.jar修改成newjacococli.jar以便进行测试。
1生成正常的覆盖率报告
执行如下命令:
java -jar ./newjacococli.jar report ./coverage-4.1.100.66230-2023-08-11-17_48_31.ec --classfiles /Users/sxf/Downloads/jacocoincrease/build_classes_12354/61/appstoreRelease/com/yiqixie/kem/im/ui/messages/roomlist/RoomListFragment.class --sourcefiles /Users/sxf/Documents/精准测试/KimCode/kim-android/packages/kim-android/eek-features/module-kim/src/main/java/ --encoding utf-8 --html ./jacoco15
没有指定diff信息可以生成指定类的全量覆盖率报告 2生成diff报告信息
通过其他的功能拿到diff文件信息格式如下所示
[{classFile:com/yiqixie/kem/im/ui/messages/roomlist/RoomListFragment,methodInfos:[{methodName:updateFolderTabLayout,parameters:[folderList: ListConversationFolderUIEntity]},{methodName:onCreate,parameters:[savedInstanceState: Bundle?]}],type:MODIFY}
]
将上面的json转换成String,执行如下命令生成增量报告 java -jar ./newjacococli.jar report ./coverage-4.1.100.66230-2023-08-11-17_48_31.ec --classfiles /Users/sxf/Downloads/jacocoincrease/build_classes_12354/61/appstoreRelease/com/yiqixie/kem/im/ui/messages/roomlist/RoomListFragment.class
--sourcefiles /Users/sxf/Documents/精准测试/KimCode/kim-android/packages/kim-android/eek-features/module-kim/src/main/java/ --encoding utf-8 --html ./jacoco16
--diffCode [{\classFile\:\com/yiqixie/kem/im/ui/messages/roomlist/RoomListFragment\,\methodInfos\:[{\methodName\:\updateFolderTabLayout\,\parameters\:[\folderList: ListConversationFolderUIEntity\]},{\methodName\:\onCreate\,\parameters\:[\savedInstanceState: Bundle?\]}],\type\:\MODIFY\}]
生成的增量报告结果如下 渲染结果如下 通过上面的测试可以达到想要的效果现在就需要再修改一下Android agent先找到diff的信息再去执行新的增量覆盖率的命令。
3) 如果diff文件过多则无法使用命令行方式
建议改成以json文件传递。
java -jar ./newjacococli.jar report ./packages/kim-android/app/build/outputs/code-coverage/connected/mergedcoverage.ec
--classfiles ./build_classes_12397/62/appstoreRelease/com/yiqixie/kem/im/ui/messages/media/MediaFragment.class
--classfiles ./build_classes_12397/62/appstoreRelease/com/yiqixie/kem/im/ui/messages/media/MediaLayout.class
--classfiles ./build_classes_12397/62/appstoreRelease/com/yiqixie/kem/im/ui/messages/media/MediaSlideActivity.class
--sourcefiles ./packages/kim-android/eek-features/module-kim/src/main/java
--sourcefiles ./packages/kim-android/eek-features/module-kim/src/main/java
--sourcefiles ./packages/kim-android/eek-features/module-kim/src/main/java
--encoding utf-8 --html ./diffreportsxf
--diffCodeFiles ./diff_files.json
5最新的生成覆盖率报告流程 通过借助于上面修改后的jacococli.jar包最新生成增量报告的流程如下所示 新的生成增量报告的方案做到了如下几点 统一对比版本和对比分支生成增量报告的逻辑最终生成jacoco格式的报告 补全了所有增量报告数据分支行函数和类的覆盖率数据都是准确的 增量方案渲染代码页覆盖情况方便测试同学根据增量函数进行排查问题。 无需修改jacoco插件不影响覆盖率数据的采集。