• jacoco统计自动化代码覆盖率


    jacoco统计自动化代码覆盖率

    1. 简介
    1.1. 什么是Jacoco
    Jacoco是一个开源的代码覆盖率工具,可以嵌入到Ant 、Maven中,并提供了EclEmma Eclipse插件,也可以使用JavaAgent技术监控Java程序。很多第三方的工具提供了对Jacoco的集成,如sonar、Jenkins等。
    1.2. 什么是代码覆盖率
    代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率。
    代码覆盖率是衡量测试质量的一个重要指标。在对一个软件产品进行了单元测试、组装测试、集成测试以及接口测试等繁多的测试之后,我们能不能就此对软件的质量产生一定的信心呢?这就需要我们对测试的质量进行考察。如果测试仅覆盖了代码的一小部分,那么不管我们写了多少测试用例,我们也不能相信软件质量是有保证的。相反,如果测试覆盖到了软件的绝大部分代码,我们就能对软件的质量有一个合理的信心。
    代码覆盖分为下面五种情况:
    1.2.1. 函数覆盖
    函数覆盖(Function Coverage),执行到程序中的每一个函数(或副程式)。
    1.2.2. 语句覆盖
    语句覆盖(Statement Coverage),又称行覆盖(Line Coverage),段覆盖(Segment Coverage),基本块覆盖(Basic Block Coverage),这是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了。这里说的是“可执行语句”,因此就不会包括像C++的头文件声明,代码注释,空行,等等。非常好理解,只统计能够执行的代码被执行了多少行。需要注意的是,单独一行的花括号{}也常常被统计进去。语句覆盖常常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等等。假如你的上司只要求你达到语句覆盖,那么你可以省下很多功夫,但是,换来的确实测试效果的不明显,很难更多地发现代码中的问题。
    1.2.3. 判断覆盖
    判断覆盖(Decision Coverage),又称分支覆盖(Branch Coverage),所有边界覆盖(All-Edges Coverage),基本路径覆盖(Basic Path Coverage),判定路径覆盖(Decision-Decision-Path)。它度量程序中每一个判定的分支是否都被测试到了。这句话是需要进一步理解的,应该非常容易和下面说到的条件覆盖混淆。因此我们直接介绍第三种覆盖方式,然后和判定覆盖一起来对比,就明白两者是怎么回事了。
    1.2.4. 条件覆盖
    条件覆盖(Condition Coverage),它度量判定中的每个子表达式结果true和false是否被测试到了。
    1.2.5. 路径覆盖
    路径覆盖(Path Coverage),又称断言覆盖(Predicate Coverage)。它度量了是否函数的每一个分支都被执行了。 这句话也非常好理解,就是所有可能的分支都执行一遍,有多个分支嵌套时,需要对多个分支进行排列组合,可想而知,测试路径随着分支的数量指数级别增加。
    1.3. Jacoco的功能
    1.3.1. 覆盖率计数器
    Jacoco使用一系列的不同的计数器来做覆盖率的度量计算。所有这些计数器都是从java的class文件中获取信息,这些class文件可以(可选)包含调试的信息在里面。即使在没有源码的情况下,这种方法也可以实时有效地对应用程序进行度量和分析。在大部分情况下,收集到的信息可以映射到源码,可视化到每一行代码的粒度。但这种方法还是有一些限制。这些class文件必须使用调试信息来编译,这样才可以计算行的覆盖率和提供出源码的高亮。但不是所有的JAVA语言的结构都可以直接编译成一致的二进制代码。在这种情况下,java 编译器会创建所谓的“合成”代码,会导致产生一些不期望得到的覆盖率结果。
    1.3.2. 指令覆盖率
    Jacoco最小的计数单元是单个java二进制代码指令。指令覆盖率提供了代码是否被执行的信息。这个度量完全独立源码格式,并且总是可用,即使class文件里面没有调试信息。
    1.3.3. 分支覆盖率
    Jacoco也计算分支的覆盖率,包括所有的if和switch语句。这个度量计算一个方法里面的总分支数,确定执行和不执行的分支数量。分支覆盖率总是可用的,即使class文件里面没有调试信息。注意异常处理是不在分支度量里面统计的。

    2. Jacoco的安装
    (1)安装ant
    首先需要安装ant和jacoco。
    下载完apache-ant的压缩包后,解压,放到常用的软件安装路径下即可。ant是基于java的,所以要先确保系统中已经安装了jdk。比如我的ant是安装在本机的,这个时候就需要配置环境变量:

     

    随后在cmd中输入命令 ant -version

    到这里就表示ant的安装已经完成了。
    (2) 在tomcat中加入jacoco
    打开tomcat的bin目录下的catalina.bat文件,在JAVA_OPTS参数中加入一行。

    脚本代码如下:

    set JAVA_OPTS=-server -Xms1024m -Xmx1024m -XX:PermSize=512M -XX:MaxNewSize=512m -XX:MaxPermSize=512m -Djava.awt.headless=true -javaagent:D:AutoTestjacocolibjacocoagent.jar=includes=com.hundsun.*,output=tcpserver,port=8229,address=127.0.0.1 -Xverify:none

    参数说明如下: 

    1) -javaagent: 的后面跟jacoco的安装路径
    2) includes= 选项,选择你要覆盖率的服务,也就是包名
    3) port=,选择你要打开的端口,jacoco的端口,与所对应的tomcat端口不能一样,与其他端口也不能冲突
    4) address= tomcat服务所在机器的ip地址(如果想在跟tomcat服务同一台机器上执行ant任务的话,需要改为127.0.0.1)
    5) -Xverify:none,避免启动报错的情况
    这样配置后就将jacoco嵌入到了tomcat中,到时候tomcat起来后,就通过开放的端口,来访问jacoco检测到的数据。正常启动tomcat,jacoco就在实时监测tomcat中运行的war包,此时数据全部存放在内存中。

    3. ant脚本
    (1) dump数据
    远程的从另外一个jvm上获取数据,并且不用停止应用的运行,这个是非常有用的。但是目标jvm需要把jacoco配置为tcpserver模式,目前使用的,也就是在tomcat的语句中,output格式为tcpserver。
    Dump数据,首先需要知道jacoco的位置和端口,然后导出exec的文件的地址,以及其他的一些配置即可。

     

     1) address:目标的jacoco的ip地址 

    2) port:目标的jacoco开放的端口号 

    3) retryCount:将尝试建立连接的重试次数。 这可以用于等待目标JVM成功启动。
    4) dump:是否转储执行数据。
    5) reset:执行导出后是否重置数据
    6) destfile:生成的数据的存放位置
    7) append:如果设置为 true,执行数据文件已存在,覆盖率数据追加到现有文件中。如果设置为 false,现有执行数据文件将被替换。
    (2) report
    report命令,需要知道exec文件的位置,以及源代码、类的位置,还有生成报告的格式需要指定。

     当涉及到多个源码包和类的时候,建议使用group的方式区分开来。 

    导出格式的选择。

    (4)完整脚本
    bulid.xml中的完整代码如下:

    <?xml version="1.0" ?>
    <project name="wftestReport" xmlns:jacoco="antlib:org.jacoco.ant" default="jacoco">
        <!--Jacoco的安装路径-->
        <property name="jacocoantPath" value="D:AutoTestjacocolibjacocoant.jar"/>
    
        <!--最终生成.exec文件的路径,Jacoco就是根据这个文件生成最终的报告的-->
        <property name="jacocoexecPath" value="D:AutoTestJREScodeCoveragemergedwftest.exec"/>
    
        <!--生成覆盖率报告的路径,直接放在tomct下面,外界直接访问-->
        <property name="reportfolderPath" value="D:AutoTestJREScodeCoverage
    eport"/>
    
        <!--远程tomcat服务的ip地址-->
        <property name="server_ip" value="127.0.0.1"/>
    
        <!--前面配置的远程tomcat服务打开的端口,要跟上面配置的一样-->
        <!--这个端口有别于tomcat的端口,相当于是嵌在tomcat里的监视器-->
        <property name="server_port" value="8229"/>
    
    
        <!--源代码路径-->
        <!--<property name="checkOrderSrcpath" value="/root/LoginDemo4/src/main/java/" />-->
        <!--可以配置多个源代码-->
        <property name="express_src" value="D:AutoTestJRESmysrcsrcmainjava"/>
    
    
        <!--.class文件路径-->
        <!--跑的是class,标注的是源码?-->
        <!--<property name="checkOrderClasspath" value="/root/wftest/target/classes/com/hundsun" />-->
    
        <property name="express_class" value="D:AutoTestJRES
    eportWEB-INFclassescomhundsun
    eportXmlexpression"/>
    
        <!--合并报告路径-->
        <property name="mergePath" value="D:AutoTestJREScodeCoverage" />
    
    
    
        <!--让ant知道去哪儿找Jacoco-->
        <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
            <classpath path="${jacocoantPath}" />
        </taskdef>
    
        <!--dump任务:
            根据前面配置的ip地址,和端口号,
            访问目标tomcat服务,并生成.exec文件。-->
        <target name="dump">
            <jacoco:dump address="${server_ip}" reset="false" destfile="${jacocoexecPath}" port="${server_port}" append="true"/>
        </target>
        <target name="merge">
            <!--将路径下的exec文件全部合并,并存放到destfile中-->
            <jacoco:merge destfile="D:AutoTestJREScodeCoveragemerged.exec">
                <fileset dir="${mergePath}" includes="*.exec"/>
            </jacoco:merge>
        </target>
    
    
    
      <!--jacoco任务:
          根据前面配置的源代码路径和.class文件路径,
          根据dump后,生成的.exec文件,生成最终的html覆盖率报告。-->
      <target name="report">
        <!--暂时不删除,一旦删除,其他两个的报告也没了--> 
          <delete dir="${reportfolderPath}" />
          <mkdir dir="${reportfolderPath}" /> 
            <jacoco:report>
                <executiondata>
                    <file file="${jacocoexecPath}" />
                </executiondata>             
                <structure name="ucf report">          
                    <group name="express related">           
                        <classfiles>
                            <fileset dir="${express_class}" />
                        </classfiles>
                        <sourcefiles encoding="utf-8">
                            <fileset dir="${express_src}" />
                        </sourcefiles>
                    </group>              
                </structure>
              <html destdir="${reportfolderPath}" encoding="utf-8" />    
              <csv destfile="D:AutoTestJREScodeCoverage
    eport.csv" />         
            </jacoco:report>
      </target>
    </project>

    (5)脚本使用
    以上内容全部放在一个build.xml中,如图所示:

    在这个目录下进行cmd命令执行,

     访问目标tomcat服务,并生成.exec文件。 

    接下来,我们可以执行命令ant report ,来生成代码覆盖报告。

     到此jacoco已经生成了代码覆盖率的报告,路径如下图所示:

     4. 报告解读 

    (1)颜色
    没有覆盖:在这一行中没有分支被执行(红色方块)
    部分覆盖:这一行的分支中只有一部分被执行(黄色方块)
    完全覆盖:这一行的所有分支都被执行(绿色方块)

     数量越多,进度条越长;红色越多,覆盖的越少。 

     指令覆盖
     分支覆盖
     行覆盖
     方法覆盖
     类覆盖

  • 相关阅读:
    spring配置初始化出错
    Java常用工具类(计算MD5,验证码随机生成,天数差值计算)
    Java基础(静态static)
    websocket使用nginx代理后连接频繁打开和关闭
    关于kafka客户端版本与服务端版本不一致导致的一次坑
    kafka
    maven常用命令含义
    pg数据库org.postgresql.util.PSQLException: ERROR: "xxx" is not a sequence
    @Param注解和@Mapper注解
    springmvc对参数接收的两个注解@RequestParam和@RequestBody
  • 原文地址:https://www.cnblogs.com/wsy0202/p/11820237.html
Copyright © 2020-2023  润新知