jacoco 增量方案使用说明书

2024-04-27 16:18

本文主要是介绍jacoco 增量方案使用说明书,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

鉴于上篇jacoco增量覆盖率实践实现了差异代码获取和jaocco二开后,很多咨询我的是测试的小伙伴,对java可能不太熟悉,想要直接使用又赶脚稍许迷茫,所以又写下这边文章来帮助迷茫中的小伙伴拉

  • 组件说明

首先说明一下实现此增量方案所依赖的组件

  1. 原生jacoco知识
  2. code-diff服务
  3. jacoco二开cli包

原生jacoco知识

首先你需要了解jacoco的实现步骤,知道单元测试覆盖率和功能测试覆盖率,而我们通常讲的增量覆盖率一般讲的也是功能测试覆盖率

其实单元测试和功能测试其实分别对应jacoco的offline模式和on-the-fly模式

offline模式就是在测试之前先对文件进行插桩,生成插过桩的class或jar包,测试插过桩的class和jar包,生成覆盖率信息到文件,最后统一处理,生成报告。

而on-the-fly模式则是JVM通过 -javaagent参数指定jar文件启动代理程序,代理程序在ClassLoader装载一个class前判断是否修改class文件,并将探针插入class文件,探针不改变原有方法的行为,只是记录是否已经执行。

实现on-the-fly模式需要一下几个步骤

1.使用启动我们应用服务的时候,需要添加jvm参数 -javaagent,如:

  -javaagent:[yourpath/]jacocoagent.jar=[option1]=[value1],[option2]=[value2]

具体实例如下:

java -javaagent:/tmp/jacoco/lib/jacocoagent.jar=includes=*,output=tcpserver,port=6300,address=localhost,append=true -jar demo-0.0.1-SNAPSHOT.jar 

其中有个几个关键参数需要我们注意

  • includes=*

这个代表了,启动时需要进行字节码插桩的包过滤,*代表所有的class文件加载都需要进行插桩。

你可以写成:

includes=com.test.service.*

       这个参数我们可以用来做maven多模块的覆盖率,比如我们只想查看service服务层的覆盖率,我们可以通过设置包路径的方式进行只统计当前包的覆盖率

  • output=tcpserver     

       output主要四个参数:

  1. file: At VM termination execution data is written to the file specified in the destfile attribute.(当jvm停止掉的时候产出dump文件,即服务挂了产出dump文件)

  2. tcpserver: The agent listens for incoming connections on the TCP port specified by the address and port attribute. Execution data is written to this TCP connection.(常用模式,将jacocoaget作为服务,每次通过cli包进行dump命令去获取dump包)

  3. tcpclient: At startup the agent connects to the TCP port specified by the address and port attribute. Execution data is written to this TCP connection.(将jacocoagent做为客户端,向指定ip和端口的服务推送dump信息)

  4. none: Do not produce any output.(不产出任何dump,dump个寂寞,忽略)

此处需要有个说明:在k8s容器里面由于ip是动态的,tcpserver模式的ip无法固定填写,可以填 0.0.0.0 然后通过实际容器 ip 就可以访问到,而这个实际ip,一般可以从cmdb服务中动态获取

  • port=98080

这是jacoco开启的tcpserver的端口,请注意这个端口不能被占用

  • address=192.168.110.1

这是对外开发的tcpserver的访问地址。可以配置127.0.0.1,也可以配置为实际访问ip
配置为127.0.0.1的时候,dump数据只能在这台服务器上进行dump,就不能通过远程方式dump数据。
配置为实际的ip地址的时候,就可以在任意一台机器上(前提是ip要通,不通都白瞎),通过ant xml或者api方式dump数据。
举个栗子:
我如上配置了192.168.110.1:2014作为jacoco的tcpserver启动服务,
那我可以在任意一台机器上进行数据的dump,比如在我本机windows上用api或者xml方式调用dump。
如果我配置了127.0.0.1:2014作为启动服务器,那么我只能在这台测试机上进行dump,其他的机器都无法连接到这个tcpserver进行dump

如果不知道本机ip地址,可以使用0.0.0.0,这样ip地址会绑定主机ip

2.我们需要使用cli包去获取exec文件

java -jar jacococli.jar dump --address 192.169.110.1 --port 2014 --destfile ./jacoco-demo.exec

使用这个命令会在我们调用方的服务上生成一个exec文件

3.生成report

java -jar jacococli.jar report ./jacoco-demo.exec --classfiles /Users/oukotoshuu/IdeaProjects/demo/target/classes/com   --classfiles /Users/oukotoshuu/IdeaProjects/demo/target/classes/com  --sourcefiles /Users/oukotoshuu/IdeaProjects/demo/src/main/java --sourcefiles /Users/oukotoshuu/IdeaProjects/demo/src/main/java --html report --xml report.xml

还是通过cli包去生成报告文件,注意这个classfiles和sourcefiles 可以是多个,我们如果是多模块项目通过指定代码路径和编译文件路径去分开做统计

以上就是jacoc原生知识点,相信大部分童鞋是清楚滴。

code-diff服务

code-diff一个获取增量代码的服务,支持git(分支,tag,commitid)和svn(分支,rversion),具体实现已经在上篇讲解到,这里只讲使用

首先拉取代码,修改配置文件,主要修改git服务的账号和密码,以及拉取代码的存储地址

1、修改application.yml
##基于git
git:userName: adminpassword: 123456local:base:dir: D:\git-test
##基于svn
svn:userName: adminpassword: 123456local:base:dir: D:\svn-test

然后运行maven命令:

mvn  clean package -Dmaven.test.skip=true 

这样就可以获取到一个code-diff.jar包

找到一个服务器,将包扔上去,然后部署:

java -jar code-diff.jar

如此我们就算部署好差异代码服务了

运行项目,访问http://127.0.0.1:8085/doc.html(地址为部署服务ip)

git差异代码获取 svn差异代码获取 输入git地址,填写差异分支的旧版本,新版本,执行,就可以获取差异信息

{"code": 10000,"msg": "业务处理成功","data": [{"classFile": "com/dr/application/InstallCert","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/app/controller/Calculable","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/app/controller/JenkinsPluginController","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/app/controller/LoginController","methodInfos": [{"methodName": "captcha","parameters": "HttpServletRequest&HttpServletResponse"},{"methodName": "login","parameters": "LoginUserParam&HttpServletRequest"},{"methodName": "testInt","parameters": "int&char"},{"methodName": "testInt","parameters": "String&int"},{"methodName": "testInt","parameters": "short&int"},{"methodName": "testInt","parameters": "int[]"},{"methodName": "testInt","parameters": "T[]"},{"methodName": "testInt","parameters": "Calculable&int&int"},{"methodName": "testInt","parameters": "Map<String,Object>&List<String>&Set<Integer>"},{"methodName": "display","parameters": ""},{"methodName": "a","parameters": "InnerClass"}],"type": "MODIFY"},{"classFile": "com/dr/application/app/controller/RoleController","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/app/controller/TestController","methodInfos": [{"methodName": "test","parameters": ""},{"methodName": "getPom","parameters": "HttpServletResponse"},{"methodName": "getDeList","parameters": ""}],"type": "MODIFY"},{"classFile": "com/dr/application/app/controller/view/RoleViewController","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/app/param/AddRoleParam","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/app/vo/DependencyVO","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/app/vo/JenkinsPluginsVO","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/app/vo/RoleVO","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/config/ExceptionAdvice","methodInfos": [{"methodName": "handleException","parameters": "Exception"},{"methodName": "handleMissingServletRequestParameterException","parameters": "MissingServletRequestParameterException"}],"type": "MODIFY"},{"classFile": "com/dr/application/config/GitConfig","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/config/JenkinsConfig","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/ddd/StaticTest","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/ddd/Test","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/application/util/GitAdapter","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/common/errorcode/BizCode","methodInfos": [{"methodName": "getCode","parameters": ""}],"type": "MODIFY"},{"classFile": "com/dr/common/response/ApiResponse","methodInfos": [{"methodName": "success","parameters": ""}],"type": "MODIFY"},{"classFile": "com/dr/jenkins/JenkinsApplication","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/config/JenkinsConfigure","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/controller/JenkinsController","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/controller/TestApi","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/dto/JobAddDto","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/service/JenkinsService","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/service/impl/JenkinsServiceImpl","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/util/GenerateUniqueIdUtil","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/vo/DeviceVo","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/vo/GoodsVO","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/jenkins/vo/JobAddVo","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/repository/user/dto/query/RoleQueryDto","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/repository/user/dto/result/RoleResultDto","methodInfos": null,"type": "ADD"},{"classFile": "com/dr/user/service/impl/PermissionServiceImpl","methodInfos": [{"methodName": "getPermissionByRoles","parameters": "List<Long>"},{"methodName": "buildMenuTree","parameters": "List<MenuDTO>"},{"methodName": "getSubMenus","parameters": "Long&Map<Long,List<MenuDTO>>"}],"type": "MODIFY"},{"classFile": "com/dr/user/service/impl/RoleServiceImpl","methodInfos": [{"methodName": "getByUserId","parameters": "Long"},{"methodName": "getListByPage","parameters": "RoleQueryDto"}],"type": "MODIFY"}],"uniqueData": "[{\"classFile\":\"com/dr/application/InstallCert\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/controller/Calculable\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/controller/JenkinsPluginController\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/controller/LoginController\",\"methodInfos\":[{\"methodName\":\"captcha\",\"parameters\":\"HttpServletRequest&HttpServletResponse\"},{\"methodName\":\"login\",\"parameters\":\"LoginUserParam&HttpServletRequest\"},{\"methodName\":\"testInt\",\"parameters\":\"int&char\"},{\"methodName\":\"testInt\",\"parameters\":\"String&int\"},{\"methodName\":\"testInt\",\"parameters\":\"short&int\"},{\"methodName\":\"testInt\",\"parameters\":\"int[]\"},{\"methodName\":\"testInt\",\"parameters\":\"T[]\"},{\"methodName\":\"testInt\",\"parameters\":\"Calculable&int&int\"},{\"methodName\":\"testInt\",\"parameters\":\"Map<String,Object>&List<String>&Set<Integer>\"},{\"methodName\":\"display\",\"parameters\":\"\"},{\"methodName\":\"a\",\"parameters\":\"InnerClass\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/application/app/controller/RoleController\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/controller/TestController\",\"methodInfos\":[{\"methodName\":\"test\",\"parameters\":\"\"},{\"methodName\":\"getPom\",\"parameters\":\"HttpServletResponse\"},{\"methodName\":\"getDeList\",\"parameters\":\"\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/application/app/controller/view/RoleViewController\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/param/AddRoleParam\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/vo/DependencyVO\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/vo/JenkinsPluginsVO\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/vo/RoleVO\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/config/ExceptionAdvice\",\"methodInfos\":[{\"methodName\":\"handleException\",\"parameters\":\"Exception\"},{\"methodName\":\"handleMissingServletRequestParameterException\",\"parameters\":\"MissingServletRequestParameterException\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/application/config/GitConfig\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/config/JenkinsConfig\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/ddd/StaticTest\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/ddd/Test\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/util/GitAdapter\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/common/errorcode/BizCode\",\"methodInfos\":[{\"methodName\":\"getCode\",\"parameters\":\"\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/common/response/ApiResponse\",\"methodInfos\":[{\"methodName\":\"success\",\"parameters\":\"\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/jenkins/JenkinsApplication\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/config/JenkinsConfigure\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/controller/JenkinsController\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/controller/TestApi\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/dto/JobAddDto\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/service/JenkinsService\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/service/impl/JenkinsServiceImpl\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/util/GenerateUniqueIdUtil\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/vo/DeviceVo\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/vo/GoodsVO\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/vo/JobAddVo\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/repository/user/dto/query/RoleQueryDto\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/repository/user/dto/result/RoleResultDto\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/user/service/impl/PermissionServiceImpl\",\"methodInfos\":[{\"methodName\":\"getPermissionByRoles\",\"parameters\":\"List<Long>\"},{\"methodName\":\"buildMenuTree\",\"parameters\":\"List<MenuDTO>\"},{\"methodName\":\"getSubMenus\",\"parameters\":\"Long&Map<Long,List<MenuDTO>>\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/user/service/impl/RoleServiceImpl\",\"methodInfos\":[{\"methodName\":\"getByUserId\",\"parameters\":\"Long\"},{\"methodName\":\"getListByPage\",\"parameters\":\"RoleQueryDto\"}],\"type\":\"MODIFY\"}]"}

在linux系统部署时请注意修改代码的基础路径和日志路径,如:

java -jar  -Dlog.path=/app/data2/devops/code-diff/logs  -Dgit.local.base.dir=/app/dat code-diff.jar

其中字段uniqueData的值为序列化差异代码的值,后续我们获取差异代码直接使用这个值即可,code-diff就是一个正常的java springboot项目,在我们使用时可以通过接口调用获取到差异代码再进行其他步骤

jacoco二开

jacoco二开主要是对cli包的改造,同时匹配code-diff产生的代码格式进行匹配,这里同样只讲使用

我们可以拿到jacoco二开代码进行编译获取我们的cli包,当然你也可以直接使用,我已经打好了包,下载地址。另外启用服务时用的agent包可以使用我的也可以不使用我的,没什么关系。

用法和原生jacoco一模一样,只是如果你要获取增量代码覆盖率,需要传递一个--diffCode的参数,其中--encoding=utf8为了防止报告乱码,diffCode为code-diff服务获取的data字段(如果是手动测试json需要转义,直接取uniqueData字段的返回结果就好,接口调用直接取data)

java -jar org.jacoco.cli-0.8.7-SNAPSHOT-nodeps.jar report jacoco.exec --classfiles \Desktop\feigin\web\build\classes
--classfiles \Desktop\feigin\biz\build\classes
--classfiles \Desktop\feigin\base\build\classes --sourcefiles \Desktop\feigin\web\src\main\java
--sourcefiles \Desktop\feigin\biz\src\main\java
--sourcefiles \Desktop\feigin\base\src\main\java --html report --xml jacoco.xml
--diffCode "[{\"classFile\":\"com/dr/application/InstallCert\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/controller/Calculable\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/controller/JenkinsPluginController\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/controller/LoginController\",\"methodInfos\":[{\"methodName\":\"captcha\",\"parameters\":\"HttpServletRequest&HttpServletResponse\"},{\"methodName\":\"login\",\"parameters\":\"LoginUserParam&HttpServletRequest\"},{\"methodName\":\"testInt\",\"parameters\":\"int&char\"},{\"methodName\":\"testInt\",\"parameters\":\"String&int\"},{\"methodName\":\"testInt\",\"parameters\":\"short&int\"},{\"methodName\":\"testInt\",\"parameters\":\"int[]\"},{\"methodName\":\"testInt\",\"parameters\":\"T[]\"},{\"methodName\":\"testInt\",\"parameters\":\"Calculable&int&int\"},{\"methodName\":\"testInt\",\"parameters\":\"Map<String,Object>&List<String>&Set<Integer>\"},{\"methodName\":\"display\",\"parameters\":\"\"},{\"methodName\":\"a\",\"parameters\":\"InnerClass\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/application/app/controller/RoleController\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/controller/TestController\",\"methodInfos\":[{\"methodName\":\"test\",\"parameters\":\"\"},{\"methodName\":\"getPom\",\"parameters\":\"HttpServletResponse\"},{\"methodName\":\"getDeList\",\"parameters\":\"\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/application/app/controller/view/RoleViewController\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/param/AddRoleParam\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/vo/DependencyVO\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/vo/JenkinsPluginsVO\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/app/vo/RoleVO\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/config/ExceptionAdvice\",\"methodInfos\":[{\"methodName\":\"handleException\",\"parameters\":\"Exception\"},{\"methodName\":\"handleMissingServletRequestParameterException\",\"parameters\":\"MissingServletRequestParameterException\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/application/config/GitConfig\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/config/JenkinsConfig\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/ddd/StaticTest\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/ddd/Test\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/application/util/GitAdapter\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/common/errorcode/BizCode\",\"methodInfos\":[{\"methodName\":\"getCode\",\"parameters\":\"\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/common/response/ApiResponse\",\"methodInfos\":[{\"methodName\":\"success\",\"parameters\":\"\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/jenkins/JenkinsApplication\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/config/JenkinsConfigure\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/controller/JenkinsController\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/controller/TestApi\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/dto/JobAddDto\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/service/JenkinsService\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/service/impl/JenkinsServiceImpl\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/util/GenerateUniqueIdUtil\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/vo/DeviceVo\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/vo/GoodsVO\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/jenkins/vo/JobAddVo\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/repository/user/dto/query/RoleQueryDto\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/repository/user/dto/result/RoleResultDto\",\"methodInfos\":[],\"type\":\"ADD\"},{\"classFile\":\"com/dr/user/service/impl/PermissionServiceImpl\",\"methodInfos\":[{\"methodName\":\"getPermissionByRoles\",\"parameters\":\"List<Long>\"},{\"methodName\":\"buildMenuTree\",\"parameters\":\"List<MenuDTO>\"},{\"methodName\":\"getSubMenus\",\"parameters\":\"Long&Map<Long,List<MenuDTO>>\"}],\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/user/service/impl/RoleServiceImpl\",\"methodInfos\":[{\"methodName\":\"getByUserId\",\"parameters\":\"Long\"},{\"methodName\":\"getListByPage\",\"parameters\":\"RoleQueryDto\"}],\"type\":\"MODIFY\"}]"
--encoding=utf8

鉴于最近有部分小伙伴们反馈window下cmd命令报gson错误,无法生成报告,

Loading execution data file D:\jacoco\jacoco-demo2.exec.
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 2
path $at com.google.gson.Gson.fromJson(Gson.java:1003)at com.google.gson.Gson.fromJson(Gson.java:956)at com.google.gson.Gson.fromJson(Gson.java:905)at org.jacoco.cli.internal.core.analysis.CoverageBuilder.<init>(CoverageBuilder.java:61)at org.jacoco.cli.internal.commands.Report.analyze(Report.java:120)at org.jacoco.cli.internal.commands.Report.execute(Report.java:91)at org.jacoco.cli.internal.Main.execute(Main.java:90)at org.jacoco.cli.internal.Main.main(Main.java:105)
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 2 path $at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350)at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80)at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)at com.google.gson.Gson.fromJson(Gson.java:991)... 7 more

我这里说明下,由于cmd命令下会对json格式进行转义,到达我们的cli程序时已经不满足json格式,所以会报这样的错误,针对上述问题,主要有一下几种解决方案:

  • 将--diffCode放到最后,json无需加引号,类似这样
java -jar jacoco-cli.jar report jacoco-demo2.exec --classfiles D:\code\code-diff\application\target\classes\com   --sourcefiles D:\code\code-diff\application\src\main\java  --html report --xml report.xml --diffCode [{\"classFile\":\"com/dr/code/diff/util/MethodParserUtils\",\"lines\":[{\"endLineNum\":76,\"startLineNum\":75,\"type\":\"REPLACE\"}],\"methodInfos\":[{\"methodName\":\"visit\",\"parameters\":[\"MethodDeclaration\",\"List<MethodInfoResult>\"]}],\"moduleName\":\"application\",\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/code/diff/controller/CodeDiffController\",\"lines\":[{\"endLineNum\":8,\"startLineNum\":7,\"type\":\"INSERT\"}],\"methodInfos\":[{\"methodName\":\"getGitList\",\"parameters\":[\"String\",\"String\",\"String\"]},{\"methodName\":\"getSvnList\",\"parameters\":[\"String\",\"String\",\"String\"]},{\"methodName\":\"getSvnBranchList\",\"parameters\":[\"String\",\"String\"]},{\"methodName\":\"getSvnBranchReversionList\",\"parameters\":[\"String\",\"String\",\"String\",\"String\"]}],\"moduleName\":\"application\",\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/code/diff/vercontrol/git/GitAbstractVersionControl\",\"lines\":[{\"endLineNum\":8,\"startLineNum\":7,\"type\":\"INSERT\"},{\"endLineNum\":30,\"startLineNum\":29,\"type\":\"REPLACE\"},{\"endLineNum\":88,\"startLineNum\":64,\"type\":\"INSERT\"}],\"methodInfos\":[{\"methodName\":\"getDiffCodeClasses\",\"parameters\":[]}],\"moduleName\":\"application\",\"type\":\"MODIFY\"},{\"classFile\":\"com/dr/code/diff/enums/GitUrlTypeEnum\",\"lines\":[{\"endLineNum\":69,\"startLineNum\":0,\"type\":\"INSERT\"}],\"methodInfos\":[],\"moduleName\":\"application\",\"type\":\"ADD\"},{\"classFile\":\"com/dr/code/diff/util/GitRepoUtil\",\"lines\":[{\"endLineNum\":4,\"startLineNum\":2,\"type\":\"INSERT\"},{\"endLineNum\":12,\"startLineNum\":9,\"type\":\"INSERT\"},{\"endLineNum\":21,\"startLineNum\":20,\"type\":\"REPLACE\"},{\"endLineNum\":25,\"startLineNum\":23,\"type\":\"INSERT\"},{\"endLineNum\":88,\"startLineNum\":43,\"type\":\"INSERT\"},{\"endLineNum\":91,\"startLineNum\":90,\"type\":\"REPLACE\"},{\"endLineNum\":100,\"startLineNum\":99,\"type\":\"REPLACE\"},{\"endLineNum\":105,\"startLineNum\":104,\"type\":\"REPLACE\"},{\"endLineNum\":115,\"startLineNum\":114,\"type\":\"REPLACE\"},{\"endLineNum\":119,\"startLineNum\":118,\"type\":\"REPLACE\"},{\"endLineNum\":163,\"startLineNum\":127,\"type\":\"INSERT\"},{\"endLineNum\":176,\"startLineNum\":175,\"type\":\"REPLACE\"},{\"endLineNum\":217,\"startLineNum\":215,\"type\":\"REPLACE\"},{\"endLineNum\":241,\"startLineNum\":223,\"type\":\"INSERT\"},{\"endLineNum\":259,\"startLineNum\":258,\"type\":\"REPLACE\"},{\"endLineNum\":263,\"startLineNum\":262,\"type\":\"INSERT\"}],\"methodInfos\":[{\"methodName\":\"instanceHttpGit\",\"parameters\":[\"String\",\"String\",\"String\",\"Git\",\"String\",\"String\"]},{\"methodName\":\"instanceSshGit\",\"parameters\":[\"String\",\"String\",\"String\",\"Git\",\"String\"]},{\"methodName\":\"createDefaultJSch\",\"parameters\":[\"FS\"]},{\"methodName\":\"configure\",\"parameters\":[\"OpenSshConfig.Host\",\"Session\"]},{\"methodName\":\"httpCloneRepository\",\"parameters\":[\"String\",\"String\",\"String\",\"String\",\"String\"]},{\"methodName\":\"sshCloneRepository\",\"parameters\":[\"String\",\"String\",\"String\",\"String\"]},{\"methodName\":\"checkGitWorkSpace\",\"parameters\":[\"String\",\"String\"]},{\"methodName\":\"judgeUrlType\",\"parameters\":[\"String\"]},{\"methodName\":\"getLocalDir\",\"parameters\":[\"String\",\"String\",\"String\"]}],\"moduleName\":\"application\",\"type\":\"MODIFY\"}]
  • 使用json文件的方案,将code-diff返回的data数据存入a.json文件
[{"classFile": "com/dr/code/diff/util/MethodParserUtils","lines": [{"endLineNum": 76,"startLineNum": 75,"type": "REPLACE"}],"methodInfos": [{"methodName": "visit","parameters": ["MethodDeclaration","List<MethodInfoResult>"]}],"moduleName": "application","type": "MODIFY"},{"classFile": "com/dr/code/diff/controller/CodeDiffController","lines": [{"endLineNum": 8,"startLineNum": 7,"type": "INSERT"}],"methodInfos": [{"methodName": "getGitList","parameters": ["String","String","String"]},{"methodName": "getSvnList","parameters": ["String","String","String"]},{"methodName": "getSvnBranchList","parameters": ["String","String"]},{"methodName": "getSvnBranchReversionList","parameters": ["String","String","String","String"]}],"moduleName": "application","type": "MODIFY"},{"classFile": "com/dr/code/diff/vercontrol/git/GitAbstractVersionControl","lines": [{"endLineNum": 8,"startLineNum": 7,"type": "INSERT"},{"endLineNum": 30,"startLineNum": 29,"type": "REPLACE"},{"endLineNum": 88,"startLineNum": 64,"type": "INSERT"}],"methodInfos": [{"methodName": "getDiffCodeClasses","parameters": []}],"moduleName": "application","type": "MODIFY"},{"classFile": "com/dr/code/diff/enums/GitUrlTypeEnum","lines": [{"endLineNum": 69,"startLineNum": 0,"type": "INSERT"}],"methodInfos": [],"moduleName": "application","type": "ADD"},{"classFile": "com/dr/code/diff/util/GitRepoUtil","lines": [{"endLineNum": 4,"startLineNum": 2,"type": "INSERT"},{"endLineNum": 12,"startLineNum": 9,"type": "INSERT"},{"endLineNum": 21,"startLineNum": 20,"type": "REPLACE"},{"endLineNum": 25,"startLineNum": 23,"type": "INSERT"},{"endLineNum": 88,"startLineNum": 43,"type": "INSERT"},{"endLineNum": 91,"startLineNum": 90,"type": "REPLACE"},{"endLineNum": 100,"startLineNum": 99,"type": "REPLACE"},{"endLineNum": 105,"startLineNum": 104,"type": "REPLACE"},{"endLineNum": 115,"startLineNum": 114,"type": "REPLACE"},{"endLineNum": 119,"startLineNum": 118,"type": "REPLACE"},{"endLineNum": 163,"startLineNum": 127,"type": "INSERT"},{"endLineNum": 176,"startLineNum": 175,"type": "REPLACE"},{"endLineNum": 217,"startLineNum": 215,"type": "REPLACE"},{"endLineNum": 241,"startLineNum": 223,"type": "INSERT"},{"endLineNum": 259,"startLineNum": 258,"type": "REPLACE"},{"endLineNum": 263,"startLineNum": 262,"type": "INSERT"}],"methodInfos": [{"methodName": "instanceHttpGit","parameters": ["String","String","String","Git","String","String"]},{"methodName": "instanceSshGit","parameters": ["String","String","String","Git","String"]},{"methodName": "createDefaultJSch","parameters": ["FS"]},{"methodName": "configure","parameters": ["OpenSshConfig.Host","Session"]},{"methodName": "httpCloneRepository","parameters": ["String","String","String","String","String"]},{"methodName": "sshCloneRepository","parameters": ["String","String","String","String"]},{"methodName": "checkGitWorkSpace","parameters": ["String","String"]},{"methodName": "judgeUrlType","parameters": ["String"]},{"methodName": "getLocalDir","parameters": ["String","String","String"]}],"moduleName": "application","type": "MODIFY"}]

然后运行命令:

java -jar jacoco-cli.jar report jacoco-demo2.exec --classfiles D:\code\code-diff\application\target\classes\com   --sourcefiles D:\code\code-diff\application\src\main\java  --html report --xml report.xml  --diffCodeFiles a.json

最后我们总结下我们的增量方案

  • cicd工具(devops服务)部署测试环境时备份源码,编译类
  • 使用agent启用应用服务
  • 调用cli(二开)的dump命令生成exec文件
  • 调用cli(二开)的report命令生成差异报告率(此处用到部署时备份的源码和编译类)

整个增量方案对原生jaocco基本无侵入,也不用源码改造,欢迎大家一起找bug,哈哈,最最后汇总所有jacoco文章

jacoco的merge源码分析

jacoco增量覆盖率实践

这篇关于jacoco 增量方案使用说明书的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/940964

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

高效+灵活,万博智云全球发布AWS无代理跨云容灾方案!

摘要 近日,万博智云推出了基于AWS的无代理跨云容灾解决方案,并与拉丁美洲,中东,亚洲的合作伙伴面向全球开展了联合发布。这一方案以AWS应用环境为基础,将HyperBDR平台的高效、灵活和成本效益优势与无代理功能相结合,为全球企业带来实现了更便捷、经济的数据保护。 一、全球联合发布 9月2日,万博智云CEO Michael Wong在线上平台发布AWS无代理跨云容灾解决方案的阐述视频,介绍了

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影