jacoco源码:https://github.com/jacoco/jacoco
参考文章:https://blog.csdn.net/tushuping/category_10738357.html
Jacoco原理
- Jacoco使用插桩方式来记录覆盖率数据,通过probe探针来注入
- 插桩:是将一段代码通过某种策略插入到另一段代码,或者替换另一段代码,来收集程序运行时的动态上下文信息
- 这里的代码既可以是字节码也可以是源码
- JaCoCo就是字节码插桩方式
- 字节码插桩的两种模式
- on-the-fly模式
- 在JVM中通过添加 -java agent 参数指定特定的 jar 文件启动 Instrumentation 的代理程序
- 代理程序会在 ClassLoader 装载一个 class 前判断是否已经转换修改了该文件,如果没有则将探针插入class文件中,探针不改变原有方法的行为,只是记录是否已经执行
- offline模式
- 在测试之前先对文件进行插桩,生成插过桩的class或jar包,测试插过桩的class和jar包,生成覆盖率信息到文件,最后再统一处理,生成报告。
- on-the-fly和offline对比
- on-the-fly更方便简单,无需提前插桩,无需考虑classpath设置问题
- on-the-fly模式
Jacoco使用-命令行方式
- 下载Jacoco:https://www.jacoco.org/jacoco/index.html
- 下载后解压,只需要用到lib下的 jacocoagent.jar 和 jacococli.jar
- 启动jacocoagent:
java -javaagent:xxx/jacocoagent.jar=includes=*,output=tcpserver,port=6300,adress=localhost,append=true -jar demo-0.0.1.jar
# emo-0.0.1.jar为被测项目jar包
# includes:需要在哪些包下面插桩,*表示所有,可以指定某个模块,比如:com.example.wms.controller
# output:覆盖率以什么方式输出,有3种方式
# 1.tcpserver:当去启动生成exec文件时,才会把所有插桩数据导出来,相当于一个服务
# 2.tcpclient:用的比较少
# 3.file:会在本地生成一个文件,当被测应用停止的时候,会把插桩数据写入该文件(用的比较少)
# adress+port:当想要访问覆盖率数据时,就需要访问 adress+port
- 生成exec文件
java -jar xxx/jacococli.jar dump --address 127.0.0.1 --port 6300 --destfile jacoco-demo.exec
# address和port指向jacocoagent启动IP和端口
# jacoco-demo.exec 为生成exec文件名
- 根据exec文件,生成report报表
java -jar xxx/jacococli.jar report jacoco-demo.exec --classfiles xxx/target/classes --sourcefiles xxx/src/main/java --html html-report --xml report.xml --encoding=utf-8
# classfiles为字节码路径
# sourcefiles为源码路径
Jacoco增量覆盖
什么是增量覆盖
- 每行代码有3种状态:新增、删除、不变
- 修改前后跑同一个测试用例,每行有4种状态:修改前覆盖/修改前未覆盖、修改后覆盖/修改后未覆盖
- 增量覆盖共有3*4=12种情况,比较重要的有:新增代码未覆盖、新增代码已覆盖、不变的代码修改前覆盖,修改后未覆盖等
增量原理
- 计算出两个版本的差异代码
- 将差异代码在report阶段传给jacoco
- 修改jacoco源码,生成报告时判断代码是否是增量代码,只有增量代码才生成报告
增量覆盖实现
- jacoco二开:https://gitee.com/Dray/jacoco
- 增量代码获取:https://gitee.com/Dray/code-diff
Jacoco使用-Apache Ant方式
参考:https://www.eclemma.org/jacoco/trunk/doc/ant.html
第一步:配置build.xml文件
- build.xml文件位置:/home/perfma/jacoco-build/***-build.xml
- 以下配置项,需要修改:
2.1 生成覆盖率报告的路径:jacocoReportPath
2.2 远程tomcat服务打开的端口:server_port_gateway
2.3 源代码路径:gatewaySrcPath
2.4 class文件路径:gatewayClassesPath
<?xml version=1.0 encoding=UTF-8?>
<project name=JaCoCo default=run xmlns:jacoco=antlib:org.jacoco.ant>
<!--Jacoco的安装路径-->
<property name=jacocoAntPath value=/home/perfma/jacoco/lib/jacocoant.jar/>
<!--最终生成.exec文件的路径,Jacoco就是根据这个文件生成最终的报告的-->
<property name=jacocoExecPath value=/home/perfma/jacocoExec/>
<!--生成覆盖率报告的路径-->
<property name=jacocoReportPath value=/home/perfma/jacoco-report/aob-tdolphin-tom/>
<!--远程tomcat服务的ip地址 xxx.xx.xxx.163(172.16.1.31)-->
<property name=server_ip_test163 value=127.0.0.1/>
<!--前面配置的远程tomcat服务打开的端口,要跟上面配置的一样-->
<property name=server_port_gateway value=9011/>
<!--源代码路径-->
<property name=gatewaySrcPath value=/home/perfma/tdolphin-tom-code/tdolphin-tom/tdolphin-tom/src/main/java/>
<!--.class文件路径-->
<property name=gatewayClassesPath value=/home/perfma/tdolphin-tom-code/tdolphin-tom/tdolphin-tom/target/classes/>
<!--让ant知道去哪儿找Jacoco-->
<taskdef uri=antlib:org.jacoco.ant resource=org/jacoco/ant/antlib.xml>
<classpath path=${jacocoAntPath}/>
</taskdef>
<target name=run>
<echo message=start.../>
<echo message=dump.../>
<antcall target=dump/>
<echo message=merge.../>
<antcall target=merge/>
<echo message=report.../>
<antcall target=report/>
<echo message=end.../>
</target>
<!--dump任务:
根据前面配置的ip地址,和端口号,访问目标tomcat服务,并生成.exec文件。-->
<target name=dump>
<jacoco:dump address=${server_ip_test163} reset=true destfile=${jacocoExecPath}/jacoco_gateway.exec port=${server_port_gateway} append=false/>
</target>
<target name=merge>
<jacoco:merge destfile=${jacocoExecPath}/merged.exec>
<fileset dir=${jacocoExecPath} includes=*.exec/>
</jacoco:merge>
</target>
<!--jacoco任务:
根据前面配置的源代码路径和.class文件路径,
根据dump后,生成的.exec文件,生成最终的html覆盖率报告。-->
<target name=report>
<jacoco:report>
<executiondata>
<file file=${jacocoExecPath}/merged.exec/>
</executiondata>
<structure name=JaCoCo Report>
<group name=coverage>
<sourcefiles encoding=UTF-8>
<fileset dir=${gatewaySrcPath}/>
</sourcefiles>
<classfiles>
<fileset dir=${gatewayClassesPath}/>
</classfiles>
</group>
</structure>
<html destdir=${jacocoReportPath} encoding=utf-8/>
<csv destfile=${jacocoReportPath}/report.csv/>
<xml destfile=${jacocoReportPath}/report.xml/>
</jacoco:report>
</target>
</project>
第二步:启动被测应用
1.修改启动命令,以tdolphin-tom-jacoco应用为例,配置如下:
📢注意:端口号需要与build.xml文件中的端口号一致
jps -l | grep tdolphin-tom-jacoco | awk -F ' ' '{print$1}' | xargs -I {} kill -9 {}
sleep 2
APP_NAME=tdolphin-tom-jacoco
PERFMA_HOME=/home/perfma
LOGS_DIR=$PERFMA_HOME/logs/${APP_NAME}
VERSION=baseversion-0.0.1-SNAPSHOT
mkdir -p $LOGS_DIR
nohup java -javaagent:/home/perfma/jacoco/lib/jacocoagent.jar=includes=*,output=tcpserver,port=9011,address=127.0.0.1 -jar ${APP_NAME}-${VERSION}.jar &
echo ${APP_NAME}-${VERSION}.jar
第三步:测试被测应用
📢注意被测应用的端口号,不要搞错了
第四步:生成报告
1.执行 ant -f build.xml 生成报告
2.打包下载整个jacocoReport文件夹到本地,打开index.html