科普文:软件架构系列之【Jacoco代码覆盖率统计利器】
实现原理:效能平台在打包部署成功之后,通知测试管理平台本次部署的需求,分支,环境,应用等信息,测试管理平台根据这些信息比对当前部署分支与master分支的代码差异,然后在用户执行案例后,通过jacoco工具生成本次测试的增量覆盖率。如在测试过程中发现bug部署多次,则最终会合并所有的覆盖率报告。二、JaCoCo基本概念行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行
一、JaCoCo简述
https://github.com/jacoco/jacoco
JaCoCo是一个开源的覆盖率工具,它针对的开发语言是java,其使用方法很灵活,可以嵌入到Ant、Maven中;可以作为Eclipse插件,可以使用其JavaAgent技术监控Java程序等等。
很多第三方的工具提供了对JaCoCo的集成,如sonar、Jenkins等。
JaCoCo包含了多种尺度的覆盖率计数器,包含指令级覆盖(Instructions,C0coverage),分支(Branches,C1coverage)、圈复杂度(CyclomaticComplexity)、行覆盖(Lines)、方法覆盖(non-abstract methods)、类覆盖(classes)
为何要使用增量覆盖率?
代码覆盖率高不能说明代码质量高,但是代码覆盖率低,意味着代码质量很可能存在一些问题。
JaCoCo增量覆盖率原理介绍
实现原理:效能平台在打包部署成功之后,通知测试管理平台本次部署的需求,分支,环境,应用等信息,测试管理平台根据这些信息比对当前部署分支与master分支的代码差异,然后在用户执行案例后,通过jacoco工具生成本次测试的增量覆盖率。如在测试过程中发现bug部署多次,则最终会合并所有的覆盖率报告。
二、JaCoCo基本概念
jacoco支持多种覆盖率的统计,包括:
- 行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行。
- 类覆盖率:度量计算class类文件是否被执行。
- 分支覆盖率:度量if和switch语句的分支覆盖情况,计算一个方法里面的总分支数,确定执行和不执行的 分支数量。
- 方法覆盖率:度量被测程序的方法执行情况,是否执行取决于方法中是否有至少一个指令被执行。
- 指令覆盖:计数单元是单个java二进制代码指令,指令覆盖率提供了代码是否被执行的信息,度量完全 独立源码格式。
- 圈复杂度:在(线性)组合中,计算在一个方法里面所有可能路径的最小数目,缺失的复杂度同样表示测 试案例没有完全覆盖到这个模块。
精准测试增量覆盖率功能使用介绍
代码覆盖率:代码覆盖率测试技术是一种常见的白盒测试技术,是衡量软件测试工作充分性和完整性的重要指标。
代码覆盖率是测试过程中已经被执行过的代码占准备测试总代码量的比例和程度,关注执行用例过程中,哪些代码被执行到了,哪些代码没有被执行到。
JaCOCo简述:一个开源的覆盖率工具,可以很方便地嵌入到Ant、Maven中,并且和很多主流的持续集成工具以及代码静态检查工具,比如jenkins和sonar等。
1、在rancher(容器平台)配置jacoco环境变量,如下示例,(注:配置时端口指定8044,且配置后要确保服务能启动成功)。具体配置如下:
JAVA_OPTS:
-javaagent:/app/data/jacoco/jacocoagent.jar=includes=*,output=tcpserver,port=8044,address=*
其中,output默认为file,不过有2个局限,一是必须停掉应用,二是只能把覆盖率数据生成到本地文件。output=tcpserver,通过这种方式启动后,会同时启动一个TCP服务端,使用lsof -i :2014命令查看端口进程。然后就能通过tcp通信,来获取覆盖率数据,即dump。dump经过TCP通信,将远程机器的覆盖率数据取到本地后,生成jacoco.exec文件,然后可以使用jacococli.jar生成HTML报告。
address:服务端地址;
port:服务端端口;
2、在测试管理平台-测试工具-精准测试配置下配置系统对应的服务、环境、IP
JaCoCo原理:jacoco使用插桩的方式来记录覆盖率数据,是通过一个probe探针来注入。
插桩模式有2种模式:on-the-fly模式和offline模式。
(1)on-the-fly模式
JVM中通过 -javaagent参数指定特定的jar文件启动Instrumentation的代理程序,代理程序在通过Class Loader装载一个class前判断是否转换修改class文件,将统计代码插入class,测试覆盖率分析在JVM执行测试代码的过程中完成。
(2)offline模式
在测试之前先对文件进行插桩,生成插过桩的class或jar包,测试插过桩的class和jar包,生成覆盖率信息到文件,最后统一处理,生成报告。
(3)on-the-fly和offline对比
on-the-fly 更方便更简单,无需提前插桩,无需考虑classpath设置问题。
存在以下情况不适合使用on-the-fly模式:
- 不支持javaagent
- 无法设置JVM参数
- 字节码需要被转换成其他虚拟机
- 动态修改字节码过程和其他agent冲突
- 无法自定义用户加载类
全量覆盖率实际操作命令如下:启动jacocoagent->cli包dump生产exec文件->cli包exec生成report报表
三、JaCoCo使用方式
3.1 Apache Ant方式
参见 http://eclemma.org/jacoco/trunk/doc/ant.html
3.2 命令行方式
参见 http://www.eclemma.org/jacoco/trunk/doc/agent.html
大概的命令:
-javaagent:[yourpath/]jacocoagent.jar=[option1]=[value1],[option2]=[value2]
其他参数可以查看上面的链接
接口测试时,我们也是使用该方式来进行,具体的说明会在下面另外说明
3.3 Apache Maven方式
参见 http://www.eclemma.org/jacoco/trunk/doc/maven.html
这种方式适合Maven的项目。
3.4 Eclipse EclDmma Plugin方式
参见 EclEmma - Java Code Coverage for Eclipse
该方式主要和eclipse集成,用户可以直观的看到覆盖率的情况
四、单元测试代码覆盖率
jacoco支持生成单元测试的覆盖率和接口测试的覆盖率,本节详细描述如何用jacoco生成单元测试覆盖率。
想要在单元测试时统计单元测试的覆盖率,有两种方式,大家可以各取
4.1 mvn命令增加参数
在执行mvn命令时,加上“org.jacoco:jacoco-maven-plugin:prepare-agent”参数即可。 示例:
mvn clean test org.jacoco:jacoco-maven-plugin:0.7.3.201502191951:prepare-agent install -Dmaven.test.failure.ignore=true
其中,jacoco-maven-plugin后面跟的是jacoco的版本; 【-Dmaven.test.failure.ignore=true】建议加上,否则如果单元测试失败,就会直接中断,不会产生.exec文件
执行以上命令后,会在当前目录下的target目录产生一个jacoco.exec文件,该文件就是覆盖率的文件:
4.2 在pom文件中添加jacoco插件
具体的配置方法如下:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.6.2.201302030002</version>
<!-- 生成的exec文件地址 -->
<configuration>
<destfile>$path/jacoco-unit.exec</destfile>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
需要注意的是,用该种方法进行jekins集成时,需要在单元测试的job中显式配置sonar的Additional properties。主要配置以下三个属性:
- -Dsonar.jacoco.reportPath
- -Dsonar.java.coveragePlugin
- -Dsonar.dynamicAnalysis
其中-Dsonar.java.coveragePlugin=jacoco和-Dsonar.dynamicAnalysis=reuseReports一般为写死的属性,而-Dsonar.jacoco.reportPath需要指定exec存放的路径
五、接口测试代码覆盖率
除了支持导出单元测试代码覆盖率以外,jacoco还支持产生接口测试覆盖率。和单元测试不同的是,接口测试的入口是人工调用相关接口或者做相关动作产生的。且由于在测试时,代码部署的环境可能有多个管理服务器,所以接口测试的exec文件一般都是通过远程dump的方式进行导出。
其中,需要配置的地方有两个:
- server端---即测试服务器
- client端---即需要分析exec文件的地方,比如jekins的节点机
5.1 server端--安装jacoco
Jacoco安装比较方便。
下载下来,随意放在一个目录,解压即可。
在官网上下载Jacoco,官网地址:EclEmma - JaCoCo Java Code Coverage Library
5.2 server端--Tomcat配置
1.进入你需要统计代码覆盖率的tomcat
cd $tomcat_path/bin
2.关闭这个tomcat的服务
3.修改 catalina.sh 的JAVA_OPTS配置
# -javaagent: 的后面跟jacoco的安装路径
# includes= 选项,选择你要覆盖率的服务
# port= 选项,选择你要打开的端口,和你tomcat的服务端口要不一样,即是一个其他人未占用的端口
# address= 选项,tomcat服务所在机器的ip地址(如果想在跟tomcat服务同一台机器上执行ant任务的话,需要改为127.0.0.1)
JAVA_OPTS="-javaagent:$jacoco_path/lib/jacocoagent.jar=includes=com.netease.yourserver.*,output=tcpserver,address=xx.xx.xx.xx,port=12345"
4.启动服务,如果发现启动主程序异常,那么在JAVA_OPTS 配置中再加一项-Xverify:none
5.3 client端--安装ant
1.从http://ant.apache.org 上下载tar.gz版ant
2.复制到/usr下
3.tar -vxzf apahce-ant-1.9.2-bin.tar.gz 解压
4.改变权限
chown -R :users apahce-ant-1.9.2
chmod -R +x apahce-ant-1.9.2
5.修改系统配置文件
vi /etc/profile
#set Ant enviroment
export ANT_HOME=/usr/apache-ant-1.9.2
export PATH=$PATH:$ANT_HOME/bin
6.立刻将配置生效
source /etc/proifle
7.测试ant是否生效
ant -version
5.4 client端--配置build.xml
防踩坑提醒:build.xml文件中的jacoco版本和sever端配置的jacoco版本最好一致,否则可能会出现“Unable to dump coverage data”错误。
client端也需要安装jacoco,并需要在client配置build.xml文件:
<?xml version="1.0" ?>
<project name="testExec" xmlns:jacoco="antlib:org.jacoco.ant" default="auto_report">
<!—value为server服务所在机器 -->
<property name=“test.server.host” value=“qa13.server.163.org” />
<!—节点机上也要放jacoco的包,path为jacoco的安装路径-->
<taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
<classpath path=“/home/qatest/jacoco/jacoco-0.7.3-20150119.233432-27/lib/jacocoant.jar” />
</taskdef>
<target name="clean_exec">
<delete file=“/home/qatest/exec/rds.exec” /> <!—需要先把之前的文件删除-->
</target>
<target name="dump">
<!—port为之前server端tomcat服务打开的端口,要和上面配置的一样-->
<!—destfile指定生成的文件地址-->
<jacoco:dump address=“${test.server.host}” port=“12345” reset=“true” destfile=“/home/qatest/exec/rds.exec” />
</target>
<target name="auto_report" depends="clean_exec,dump" />
</project>
如果是多模块,则build.xml文件的配置如下:
<?xml version="1.0" ?>
<project name="testExec" xmlns:jacoco="antlib:org.jacoco.ant" default="auto_report">
<property name="test.server.host" value="127.0.0.1" />
<taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
<classpath path="/home/ndir/jacoco/jacoco-0.7.3-20150119.233432-27/lib/jacocoant.jar" />
</taskdef>
<target name="clean_exec">
<delete dir="/home/ndir/report/exec" />
<delete dir="/home/ndir/report/report" />
<delete file="/home/ndir/report/merged.exec" />
</target>
<target nam
e="dump">
<jacoco:dump address="${test.server.host}" port="12347" reset="true" destfile="/home/ndir/report/exec/indexStore1.exec" />
<jacoco:dump address="${test.server.host}" port="12348" reset="true" destfile="/home/ndir/report/exec/indexStore2.exec" />
<jacoco:dump address="${test.server.host}" port="12346" reset="true" destfile="/home/ndir/report/exec/logQueue.exec" />
<jacoco:dump address="${test.server.host}" port="12349" reset="true" destfile="/home/ndir/report/exec/searchDispatcher.exec" />
<jacoco:dump address="${test.server.host}" port="12345" reset="true" destfile="/home/ndir/report/exec/indexDispatcher.exec" />
</target>
<target name="merge_exec">
<jacoco:merge destfile="/home/ndir/report/merged.exec">
<fileset dir="/home/ndir/report/exec" includes="*.exec" />
</jacoco:merge>
</target>
<target name="auto_report" depends="clean_exec,dump,merge_exec" />
</project>
进行如上配置后,在sever端进行测试,并在client端执行ant dump后,即可在指定目录将远程server端的代码覆盖率dump出来。
六、与Jekins集成
jacoco生成的覆盖率文件是.exec文件,该文件可以用sonar或者jekins中的Jacoco plugin直接生成覆盖率报告,并在Jenkins中生成图表等等。
这边主要讲下在jekins上和sonar的结合。
假设现在我们通过jacoco已经拿到了单元测试或者接口测试的覆盖率文件,那么如何通过jekins进行分析呢?方法也非常简单,主要需要增加一个job,用来读取生成的文件,并通过sonar进行分析
6.1 配置shell,读取exec文件
这样,就可以在sonar上看到单元测试覆盖率和接口测试覆盖率,并有总体覆盖率可以查看
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)