JAVA代码覆盖率统计利器Jacoco

JaCoCo介绍

一、JaCoCo简述

JaCoCo是一个开源的覆盖率工具,它针对的开发语言是java,其使用方法很灵活,可以嵌入到Ant、Maven中;可以作为Eclipse插件,可以使用其JavaAgent技术监控Java程序等等。

很多第三方的工具提供了对JaCoCo的集成,如sonar、Jenkins等。

JaCoCo包含了多种尺度的覆盖率计数器,包含指令级覆盖(Instructions,C0coverage),分支(Branches,C1coverage)、圈复杂度(CyclomaticComplexity)、行覆盖(Lines)、方法覆盖(non-abstract methods)、类覆盖(classes)

二、JaCoCo基本概念

jacoco支持多种覆盖率的统计,包括:

  1. 行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行。
  2. 类覆盖率:度量计算class类文件是否被执行。
  3. 分支覆盖率:度量if和switch语句的分支覆盖情况,计算一个方法里面的总分支数,确定执行和不执行的 分支数量。
  4. 方法覆盖率:度量被测程序的方法执行情况,是否执行取决于方法中是否有至少一个指令被执行。
  5. 指令覆盖:计数单元是单个java二进制代码指令,指令覆盖率提供了代码是否被执行的信息,度量完全 独立源码格式。
  6. 圈复杂度:在(线性)组合中,计算在一个方法里面所有可能路径的最小数目,缺失的复杂度同样表示测 试案例没有完全覆盖到这个模块。

三、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方式

参见 http://www.eclemma.org/

该方式主要和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文件,该文件就是覆盖率的文件:

总体说来,这种方式比较简单,在与jekins集成时也非常方便,推荐大家用这种方式进行配置。

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,官网地址:http://eclemma.org/jacoco/

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文件


6.2 配置sonar,对结果进行分析


6.3 查看结果


这样,就可以在sonar上看到单元测试覆盖率和接口测试覆盖率,并有总体覆盖率可以查看

网易云新用户大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者徐晗授权发布。