zoukankan      html  css  js  c++  java
  • 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)颜色
    没有覆盖:在这一行中没有分支被执行(红色方块)
    部分覆盖:这一行的分支中只有一部分被执行(黄色方块)
    完全覆盖:这一行的所有分支都被执行(绿色方块)

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

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

  • 相关阅读:
    627. Swap Salary
    176. Second Highest Salary
    596. Classes More Than 5 Students
    183. Customers Who Never Order
    181. Employees Earning More Than Their Managers
    182. Duplicate Emails
    175. Combine Two Tables
    620. Not Boring Movies
    595. Big Countries
    HDU 6034 Balala Power! (贪心+坑题)
  • 原文地址:https://www.cnblogs.com/wsy0202/p/11820237.html
Copyright © 2011-2022 走看看