JACOCO搭建指南

JACOCO是什么

JaCoCo是Java的免费代码覆盖库,由EclEmma团队基于多年的使用和整合现有库所获得的经验而创建。JACOCO官网地址:http://www.jacoco.org/jacoco/, 下载最新版 JACOCO

使用JACOCO代理收集覆盖率数据

JaCoCo使用类文件检测来记录执行范围数据。Class文件使用一个所谓的Java代理进行实时检测。该机制允许在类加载期间独立于应用程序框架的所有类文件的内存预处理。
JaCoCo代理收集执行信息,并根据请求或JVM退出时转储它。执行数据输出有三种不同的模式:

file:在JVM终止处执行数据被写入本地文件。

tcpserver:外部工具可以连接到JVM并通过套接字连接检索执行数据。在VM退出时可选的执行数据重置和执行数据转储。

tcpclient:在启动时,JaCoCo代理连接到给定的TCP端点。执行数据根据请求写入套接字连接。在VM退出时可选的执行数据重置和执行数据转储。

代理jacocoagent.jar是JaCoCo发行版的一部分,包含所有必需的依赖关系。可以使用以下JVM选项激活Java代理:

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

JaCoCo代理接受以下选项:

选项 描述 默认
destfile 执行数据的输出文件的路径。 jacoco.exec
append 如果设置为true并且执行数据文件已经存在,则将覆盖数据附加到现有文件。如果设置为 false,则将替换现有的执行数据文件。 true
includes 执行分析中应包含的类名列表。列表条目以冒号(:)分隔,可以使用通配符(*和?)。除了性能优化或技术角落案例,通常不需要此选项。 * (所有类)
excludes 应从执行分析中排除的类名称列表。列表条目以冒号(:)分隔,可以使用通配符(*和?)。除了性能优化或技术角落案例,通常不需要此选项。 空(不排除类)
exclclassloader 应从执行分析中排除的类加载器名称的列表。列表条目以冒号(:)分隔,可以使用通配符(*和 ?)。如果特殊框架与JaCoCo代码工具发生冲突,特别是无法访问Java运行时类的类加载器,则可能需要此选项。 sun.reflect.DelegatingClassLoader
inclbootstrapclasses 指定是否还应该检测引导类加载器的类。谨慎使用此功能,需要大量包括/不包括调整。 false
inclnolocationclasses 指定是否还应该检测没有源位置的类。通常这样的类是在运行时产生的,例如通过模拟框架,因此在默认情况下被排除。 false
sessionid 与执行数据一起写入的会话标识符。没有这个参数,代理就会创建一个随机的标识符。 自动生成
dumponexit 如果设置为true覆盖数据,将在VM关闭时写入。如果file指定了转储,或者输出为tcpserver/ tcpclient 并且在虚拟机终止时连接处于打开状态,则只能写入转储。 true
output 用于写入覆盖率数据的输出方法。有效的选项是:
file:在虚拟机终止执行数据写入destfile属性中指定的文件。
tcpserver:代理侦听由address和port属性指定的TCP端口上的传入连接。执行数据被写入到这个TCP连接。
tcpclient:启动时,代理将连接到由address和port属性指定的TCP端口。执行数据被写入到这个TCP连接。
none:不要产生任何输出。
请参阅下面的安全考虑。
file
address 当输出方法为tcpserver或连接到 输出方法时要绑定的IP地址或主机名 tcpclient。在tcpserver模式中,值“ *”使代理接受任何本地地址上的连接。 回环接口
port 当输出方法是绑定的端口,tcpserver或者当输出方法是连接的端口tcpclient。在 tcpserver模式下,端口必须可用,这意味着如果多个JaCoCo代理应该在同一台机器上运行,则必须指定不同的端口。 6300
classdumpdir agent所调用到的所有class文件的目录。这可以用于调试目的,或者在动态创建类的情况下,例如当使用脚本引擎时。 没有转储
jmx 如果设置为true代理通过名称下的JMX 公开 功能org.jacoco:type=Runtime。请参阅下面的安全考虑。 false

配置tomcat

因我们的应用是docker镜像,所以测试的tomcat也选择了docker版。
启动tomcat时,需要与宿主机绑定端口,jacoco代理端口配置为8888

docker run --name tomcat -p 8080:8080 -p 8888:8888 tomcat

将下载来的jacoco拷贝到docker中

docker cp D:\autoTest\jacoco tomcat:/home

将docker中的tomcat启动脚本catalina.sh拷贝到宿主机进行修改

docker cp tomcat:/usr/local/tomcat/bin/catalina.sh D:\autoTest\catalina.sh

打开catalina.sh,在合适的位置增加一行

JAVA_OPTS="$JAVA_OPTS -javaagent:/home/jacoco/lib/jacocoagent.jar=output=tcpserver,address=*,port=8888,destfile=/home/jacoco.exec,append=true,classdumpdir=/usr/local/tomcat/webapps/examples/WEB-INF"

将catalina.sh文件拷贝回tomcat

docker cp D:\autoTest\catalina.sh tomcat:/usr/local/tomcat/bin/catalina.sh

重启tomcat

docker restart tomcat

配置jenkins

进入jenkins的插件管理中心,搜索插件JaCoCo plugin并安装jacoco插件
创建ant的build.xml文件

<project xmlns:jacoco="antlib:org.jacoco.ant" name="Dump JaCoCo" default="dump">
    <!--Jacoco ant lib的安装路径-->
    <property name="jacoco.ant.lib" location="./lib/jacocoant.jar"/>
    <!--最终生成.exec文件的路径,Jacoco就是根据这个文件生成最终的报告的-->
    <property name="result.exec.file" location="./jacoco.exec"/>
    <!--远程tomcat服务的ip地址-->
    <property name="jacoco.server.address" value="172.20.17.84"/>
    <!--远程tomcat服务中jacoco的端口-->
    <property name="jacoco.server.port" value="8888"/>
    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
        <classpath path="{jacoco.ant.lib}"/>                        {jacoco.server.port}" reset="true" destfile="{result.exec.file}" append="true"/>
    </target>
</project>

将创建好的build.xml和jacoco lib库上传到SVN中,注意build.xml中配置的jacoco lib的路径,需要在svn中存在。
在Jenkins中创建一个jacoco构建项目,配置好SVN,在“增加构建步骤”中添加“Invoke Ant”,在“Targets”中填写“dump”
在“增加构建后操作步骤”中添加“Record JaCoCo coverage report”,根据页面说明配置相应的配置项,保存项目,构建即可。
file

报告指标说明

file

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

file

标示绿色的为行覆盖充分,标红色的为未覆盖的行,黄色菱形的为分支部分覆盖,绿色菱形为分支完全覆盖。