jacoco与jenkins集成实现代码覆盖率分析

Posted 58招聘技术团队

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jacoco与jenkins集成实现代码覆盖率分析相关的知识,希望对你有一定的参考价值。

       

代码覆盖率引入的背景:


        平时的测试中,主要是通过case(功能及自动化)来测试被测代码,但case的的覆盖情况无法明确评估。通过case评审,我们只能依托于业务经验,从技术,产品的角度来主观评估case对需求覆盖效果。所以需要一个能客观来衡量case对代码覆盖效果的工具,通过调研发现了目前比较通用的代码覆盖率工具jacoco,目前行业里面有那么3款主流额覆盖率工具,大家可以自行百科一下。


jaoco介绍:


        JaCoCo是字节码注入方式,它是通过一个Probe探针的方式来注入的,具体如下:探针是字节指令集插入到java方法中,程序执行后可以被记录,它不会改变原有代码的行为。


jacoco的优缺点:


        JaCoCo提供了自己的Agent,JVM中通过-javaagent参数指定特定的jar文件启动Instrumentation的代理程序,代理程序在通过Class Loader装载一个class前判断是否转换修改class文件,将统计代码插入class,测试覆盖率分析可以在JVM执行测试代码的过程中完成。完成插桩的同时,还提供了丰富的dump输出机制,如File,Tcp Server,Tcp Client。覆盖率信息可以通过文件或是Tcp的形式输出。这样外部程序可很方便随时拿到被测程序的覆盖率。

        Jacoco使用一系列的不同的计数器来做覆盖率的度量计算。所有这些计数器都是从java的class文件中获取信息,这些class文件可以(可选)包含调试的信息在里面。即使在没有源码的情况下,这种方法也可以实时有效地对应用程序进行度量和分析。在大部分情况下,收集到的信息可以映射到源码,可视化到每一行代码的粒度。但这种方法还是有一些限制。这些class文件必须使用调试信息来编译,这样才可以计算行的覆盖率和提供出源码的高亮。但不是所有的JAVA语言的结构都可以直接编译成一致的二进制代码。在这种情况下,java 编译器会创建所谓的“合成”代码,会导致产生一些不期望得到的覆盖率结果。


jacoco统计维度:


指令(C0 Coverage)

        Jacoco最小的计数单元是单个java二进制代码指令。指令覆盖率提供了代码是否被执行的信息。这个度量完全独立源码格式,并且总是可用,即使class文件里面没有调试信息。

分支(C1 Coverage)

        Jacoco也计算分支的覆盖率,包括所有的if和switch语句。这个度量计算一个方法里面的总分支数,确定执行和不执行的分支数量。分支覆盖率总是可用的,即使class文件里面没有调试信息。注意异常处理是不在分支度量里面统计的。

如果class文件使用调试信息编译的话,产生的覆盖率可以映射到源码行并且高亮提示:

· 没有覆盖:在这一行中没有分支被执行(红色方块)

· 部分覆盖:这一行的分支中只有一部分被执行(黄色方块)

· 完全覆盖:这一行的所有分支都被执行(绿色方块)

圈复杂度

        Jacoco同样可以为每一个非抽象方法计算复杂度,最终计算出类、包和组的复杂度。根据由McCabe1996圈复杂度的定义是,在(线性)组合中,计算在一个方法里面所有可能路径的最小数目。所以复杂度可以作为度量单元测试是否有完全覆盖所有场景的一个依据。复杂度即使是在没有调试信息的情况下也可以计算。

E是边界的数量,N是节点的数量。Jacoco 基于下面的方程来计算复杂度,B是分支的数量,D是决策点的数量:

v(G) = B – D + 1

        基于每个分支的被覆盖情况,Jacoco也为每个方法计算覆盖和缺失的复杂度。缺失的复杂度同样表示测试案例没有完全覆盖到这个模块。注意Jacoco不将异常处理作为分支,try/catch块也同样不增加复杂度。

        所有的class文件使用debug信息编译之后,就可以计算行的覆盖率信息。一行源代码是否被执行,要看这一行中是否至少有一个指令被执行。

由于实际上一行代码一般被编译成多个二进制代码指令,这样源码在高亮显示时,会显示成3种不同的状态:

·  没有覆盖:这一行中没有指令被执行(红色背景)

·  部分覆盖:这一行中只有一部分指令被执行(黄色背景)

· 完全覆盖:这一行中所有指令都被覆盖(绿色背景

方法

        每一个非抽象方法至少包含一个指令。一个方法是否执行取决于方法中是否有至少一个指令被执行。在Jacoco中,构造器和静态初始化同样会像方法一样统计。其中一些方法可能没有可以直接对应的源码,比如默认构造器或常量的初始化命令。

        一个方法是否执行取决于类中是否有至少一个方法被执行。注意Jacoco认为构造器和静态初始化都是方法。Java的接口一般包含静态初始化,所以接口也同样被认为是可执行的类


jacoco生成报告的两种方式


1、shutdown jvm时dump出覆盖率数据

2、不停jvm dump出覆盖率数据,这样的方式下启动tomcat之后,jacoco会在一个端口上提供client访问,并能dump出此时的覆盖率数据文件。(我采用这种生成报告的形式)


使用jacoco统计代码覆盖率方法及步骤


第一步上传jacocoangent.jar和jacocoant.jar到/opt/soft/jacoco/lib目录下(一台机器上多个服务都可以用的jar包)

jacoco与jenkins集成实现代码覆盖率分析



修改被测服务的启动脚本start.sh,实现插桩:

增加 "-javaagent:/opt/soft/jacoco/lib/jacocoagent.jar=includes=*,:wqoutput=tcpserver,port=8893,address=127.0.0.1"

修改启动脚本前,必须先停掉服务

解析一下各个参数的含义:

 

然后启动服务,【如果启动服务时异常或者失败的话,可能是jar有问题(jacocoangent.jar),我刚开始遇到坑就是官网下的包有问题找不到主函数入口】

第二步:配置ant

现把包放到/opt/soft/ant目录下 配置环境变量,请参考http://blog.sina.com.cn/s/blog_677e6b240102v37h.html

 

第三步配置build.xml文件一下参数的说明,详情文档里已经标明,参数的含义如下,没有路径需要自己创建

jacoco与jenkins集成实现代码覆盖率分析

 

jacoco与jenkins集成实现代码覆盖率分析


第四步:

执行ant dump。【成功的话,jacoco.exec文件会有数据,如果此文件为空,是不能生成报告的】

在执行ant report,即可在report目录下生成报告率文件

与jenkins的集成方案:


        以上方法步骤使用jacoco统计是单个的服务代码覆盖率。由于一些历史原因我们现在的服务部署用的自己搭建的jenkins平台,为了减少覆盖率相关工作手动操作,就可以把一些重复的准备工作集成到jenkins平台的服务的部署job中,job部署完服务之后,再通过jenkins平台调用生成覆盖率报告job。为了查看报告方便,建议在Linux上装一个文件服务器(我装的是Apache),然后通过浏览器直接查看覆盖率报告。覆盖率集成到jenkins发布平台架构图:


jacoco与jenkins集成实现代码覆盖率分析



下面是两个job的执行流程图


jacoco与jenkins集成实现代码覆盖率分析



执行生成报告需要传的参数:

jacoco与jenkins集成实现代码覆盖率分析


在浏览器看到覆盖率报告展示


解决方案复杂度及使用分析:

  1. 上面介绍的准备工作的job是对已有发布job的扩展,所以用户无感知

  2. 生成报告的job在用户需要查看报告的时候手动触发,当然也可以通过jenkins的定时功能自动触发,后面规划在发布沙箱预上线环境的时候自动触发该job,得到测试环境的覆盖率,这样可以用来评估沙箱环境的重点测试覆盖。

  3. jacoco的jenkins插件可以很直关的展示覆盖信息,目前不计划对此功能进行二次开发。


总结:jacoco统计代码覆盖率的整体实现流程


确定插桩方式-》代码插桩-》打包覆盖率-》执行测试-》覆盖率结果-》生成报告-》分析覆盖率结果

 







以上是关于jacoco与jenkins集成实现代码覆盖率分析的主要内容,如果未能解决你的问题,请参考以下文章

sonar+Jenkins代码覆盖率检测

Maven工程配置代码覆盖工具Jacoco

Maven工程配置代码覆盖工具Jacoco

jenkins插件--Cobertura,JaCoCo,Emma-----

Jenkins中用jacoco统计gradle项目的代码覆盖率

Jacoco在eclipse上的集成使用