maven单测生成覆盖率报告---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集成,用户可以直观的看到覆盖率的情况

四、maven配置JaCoCo

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

具体的配置方法如下:

1.添加依賴

<dependency>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.3</version>
</dependency>

2.配置plugins

      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.3</version>
        <configuration>
          <includes>
            <include>com/**/*</include>
          </includes>
        </configuration>
        <executions>
          <execution>
            <id>pre-test</id>
            <goals>
              <goal>prepare-agent</goal>
            </goals>
          </execution>
          <execution>
            <id>post-test</id>
            <phase>test</phase>
            <goals>
              <goal>report</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

其中包含(includes)或排除(excludes)字段的值应该是相对于目录/ classes /的编译类的类路径(而不是包名),使用标准通配符语法:

*   Match zero or more characters
**  Match zero or more directories
?   Match a single character

你也可以这样排除一个包和它的所有子包/子包:

<exclude>com/src/**/*</exclude>

这将排除某些包装中的每个课程,以及任何孩子。例如,com.src.child也不会包含在报表中。

也可以在pom中指定筛选规则:

      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>${jacoco.version}</version>
        <configuration>
          <includes>
            <include>com/src/**/*</include>
          </includes>
          <!-- rules裏面指定覆蓋規則 -->
          <rules>
            <rule implementation="org.jacoco.maven.RuleConfiguration">
              <element>BUNDLE</element>
              <limits>  
                <!-- 指定方法覆蓋到50% -->
                <limit implementation="org.jacoco.report.check.Limit">
                  <counter>METHOD</counter>
                  <value>COVEREDRATIO</value>
                  <minimum>0.50</minimum>
                </limit>
                <!-- 指定分支覆蓋到50% -->
                <limit implementation="org.jacoco.report.check.Limit">
                  <counter>BRANCH</counter>
                  <value>COVEREDRATIO</value>
                  <minimum>0.50</minimum>
                </limit>
                <!-- 指定類覆蓋到100%,不能遺失任何類 -->
                <limit implementation="org.jacoco.report.check.Limit">
                  <counter>CLASS</counter>
                  <value>MISSEDCOUNT</value>
                  <maximum>0</maximum>
                </limit>
              </limits>
            </rule>
          </rules>
        </configuration>
        <executions>
          <execution>
            <id>pre-test</id>
            <goals>
              <goal>prepare-agent</goal>
            </goals>
          </execution>
          <execution>
            <id>post-test</id>
            <phase>test</phase>
            <goals>
              <goal>report</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

此时运行mvn test生成index.html(即覆盖率报告)位置在:

也可以指定输出目录:

<execution>
    <id>post-unit-test</id>
    <phase>test</phase>
    <goals>
        <goal>report</goal>
    </goals>
    <configuration>
        <dataFile>target/jacoco.exec</dataFile>
        <outputDirectory>target/jacoco-ut</outputDirectory>
    </configuration>
</execution>

在这里,我们将单元测试结果的输出目录确定为target/jacoco-ut目录下~

提交扫描结果到sonar

		<profile>
			<id>sonar</id>
			<activation>
				<activeByDefault>true</activeByDefault>
			</activation>
			<properties>
				<!-- mvn clean test org.jacoco:jacoco-maven-plugin:0.8.1:prepare-agent install -Dmaven.test.failure.ignore=true sonar:sonar -->
				<!--jacoco 跑覆盖-->
				<sonar.host.url>http://sonar.example.com</sonar.host.url>
				<!-- mvn sonar:sonar 使用此命令进行提交 -->
				<!-- 全包扫描 也可以指定具体的类,使用","分割多个类或者目录 mvn sonar:sonar -Dsonar.inclusions=src/main/java/com/jd/aibi2/share/service/ExampleImpl.java -->
				<!--<sonar.inclusions>src/main/java/com/example/service/**</sonar.inclusions>-->
				<sonar.inclusions>
					src/main/java/com/jd/example/service/impl/Xx.java,
					src/main/java/com/jd/example/service/sdk/impl/Aa.java,
					src/main/java/com/jd/example/service/impl/Bb.java
				</sonar.inclusions>
				<!--排除某些目录-->
				<sonar.exclusions>
					src/main/java/com/example/rpc/**, src/main/java/com/example/common/**,
					src/main/java/com/example/domain/**, src/main/java/com/example/sdk/**,
					src/main/java/com/example/web/**
				</sonar.exclusions>
				<sonar.projectKey>
					${project.groupId}:${project.artifactId}
				</sonar.projectKey>
				<sonar.projectName>
					${project.artifactId}
				</sonar.projectName>
				<sonar.projectVersion>
					${project.version}
				</sonar.projectVersion>
			</properties>
		</profile>
posted @ 2023-02-08 17:16  itwetouch  阅读(541)  评论(0编辑  收藏  举报