单元测试是保证代码质量的重要一环,而如何衡量单元测试写得好不好呢? 覆盖率(Coverage) 是一个重要指标。而 JaCoCo 则是专门为 Java 提供的用于检测测试覆盖率的工具,英文全称为 Java Code Coverage 。
本文将讲解如何在 Maven 项目中整合 JaCoCo ,并在 SonarQube 中展示。 SonarQube 的安装可以参考这篇文章:
《 Docker搭建代码检测平台SonarQube并检测maven项目 》
这里所讲的 覆盖率 是指测试代码的覆盖率,这个指标有多种计算方式,如下是比较常用的有:
行覆盖率:执行代码行数 / 总代码行数,判断有多少行代码被测试执行;
类覆盖率:执行的类 / 代码中类总个数;
分支覆盖率:执行的逻辑分支数 / 总的分支数,一般用于检测是不是 lf/else 都有测试覆盖;
方法覆盖率:执行的方法数 / 代码总方法数,检测是否有方法被遗漏,构造方法也看作为方法。
圈复杂度:用于判断代码结构的复杂程序, JaCoCo 不考虑异常处理的分支;一般认为圈复杂度大于10,就存在比较大的风险,严格要求不可大于15。
颜色标识:
JaCoCo 会通过颜色来标识代码覆盖情况,使其一目了然。红色表示没有覆盖,绿色表示已经覆盖,黄色表示部分覆盖。
执行方式:
执行 JaCoCo 有多种方式:
(1)直接通过命令执行: https://www.eclemma.org/jacoco/trunk/doc/agent.html
(2)Ant执行: https://www.eclemma.org/jacoco/trunk/doc/ant.html
(3)Maven执行: https://www.eclemma.org/jacoco/trunk/doc/maven.html
(4)集成IDE执行: https://www.eclemma.org/
我们接下来主要讲解 maven 的方式。
Maven 整合 JaCoCo 也容易,配置如下:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<configuration>
<skip>${maven.test.skip}</skip>
<destFile>${basedir}/target/coverage-reports/jacoco-unit.exec</destFile>
<dataFile>${basedir}/target/coverage-reports/jacoco-unit.exec</dataFile>
<output>file</output>
<append>true</append>
<excludes>
<exclude>com/pkslow/basic/containsperformance/**</exclude>
<exclude>com/pkslow/basic/ReadPropertiesFile</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<phase>test-compile</phase>
</execution>
<execution>
<id>jacoco-site</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
执行 mvn clean test ,则会生成报告 target/coverage-reports/jacoco-unit.exec ,但这是人不可读的, Sonar 可读的。 Intellij Idea 也可以阅读,按照 Run--Show Code Coverage Data 打开即可。
执行 mvn clean verify ,就会生成报告 target/site/jacoco/ ,有多种格式,用浏览器打开 index.html 文件可以方便查看。如下图所示:
指定某些类不执行检测:
<excludes> <exclude>com/pkslow/basic/containsperformance/**</exclude> <exclude>com/pkslow/basic/ReadPropertiesFile</exclude> </excludes>
Rules 标签可以指定检查阈值,比如类覆盖率必须为 100% 。在 configuration 里面配置如下:
<rules>
<rule implementation="org.jacoco.maven.RuleConfiguration">
<element>BUNDLE</element>
<limits>
<limit implementation="org.jacoco.report.check.Limit">
<counter>METHOD</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
<limit implementation="org.jacoco.report.check.Limit">
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
<limit implementation="org.jacoco.report.check.Limit">
<counter>CLASS</counter>
<value>MISSEDCOUNT</value>
<maximum>0</maximum>
</limit>
</limits>
</rule>
</rules>
这时需要有下面的 check 才会执行这个规则校验:
<execution>
<id>check</id>
<goals>
<goal>check</goal>
</goals>
</execution>
如果不满足条件, maven build 就会失败。不过,如果我们集成了 SonarQube ,我们则会通过 SonarQube 来设置这个规则和阈值。
添加 SonarQube 配置信息如下,有三种配置方式:
(1)配置数据库信息
<profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<sonar.jdbc.url>jdbc:postgresql://localhost/sonar</sonar.jdbc.url>
<sonar.jdbc.driver>org.postgresql.Driver</sonar.jdbc.driver>
<sonar.jdbc.username>user</sonar.jdbc.username>
<sonar.jdbc.password>password</sonar.jdbc.password>
<sonar.host.url>http://localhost:9000</sonar.host.url>
</properties>
</profile>
</profiles>
(2)配置用户名密码
<profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<sonar.host.url>http://localhost:9000</sonar.host.url>
<sonar.login>admin</sonar.login>
<sonar.password>admin</sonar.password>
</properties>
</profile>
</profiles>
(3)配置令牌
<profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<sonar.host.url>http://localhost:9000</sonar.host.url>
<sonar.login>9656c84090b2481db6ea97b6d14d87d546bff619</sonar.login>
</properties>
</profile>
</profiles>
以上三种都可以,配置完成后,执行命令如下:
mvn clean verify sonar:sonar
如果不想添加配置,可以直接通过命令来指定,命令如下:
mvn clean verify sonar:sonar -Dsonar.host.url=http://localhost:9000 -Dsonar.login=9656c84090b2481db6ea97b6d14d87d546bff619
JaCoCo 对项目质量管理作用重大,应该加以使用。最终的maven配置文件 pom.xml 行数太大,请到( https://www.pkslow.com/archives/maven-jacoco-sonar )参考。
整合以后,最终的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.larry</groupId>
<artifactId>JavaBasic</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<configuration>
<skip>${maven.test.skip}</skip>
<destFile>${basedir}/target/coverage-reports/jacoco-unit.exec</destFile>
<dataFile>${basedir}/target/coverage-reports/jacoco-unit.exec</dataFile>
<output>file</output>
<append>true</append>
<excludes>
<exclude>com/pkslow/basic/containsperformance/**</exclude>
<exclude>com/pkslow/basic/ReadPropertiesFile</exclude>
</excludes>
<rules>
<rule implementation="org.jacoco.maven.RuleConfiguration">
<element>BUNDLE</element>
<limits>
<limit implementation="org.jacoco.report.check.Limit">
<counter>METHOD</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
<limit implementation="org.jacoco.report.check.Limit">
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
<limit implementation="org.jacoco.report.check.Limit">
<counter>CLASS</counter>
<value>MISSEDCOUNT</value>
<maximum>0</maximum>
</limit>
</limits>
</rule>
</rules>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<phase>test-compile</phase>
</execution>
<!-- <execution>-->
<!-- <id>check</id>-->
<!-- <goals>-->
<!-- <goal>check</goal>-->
<!-- </goals>-->
<!-- </execution>-->
<execution>
<id>jacoco-site</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- <sonar.jdbc.url>jdbc:postgresql://localhost/sonar</sonar.jdbc.url>-->
<!-- <sonar.jdbc.driver>org.postgresql.Driver</sonar.jdbc.driver>-->
<!-- <sonar.jdbc.username>user</sonar.jdbc.username>-->
<!-- <sonar.jdbc.password>password</sonar.jdbc.password>-->
<sonar.host.url>http://localhost:9000</sonar.host.url>
<!-- <sonar.login>admin</sonar.login>-->
<!-- <sonar.password>admin</sonar.password>-->
<sonar.login>9656c84090b2481db6ea97b6d14d87d546bff619</sonar.login>
</properties>
</profile>
</profiles>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<jacoco.version>0.8.5</jacoco.version>
</properties>
</project>
欢迎访问 南瓜慢说 www.pkslow.com 获取更多精彩文章!
欢迎关注微信公众号< 南瓜慢说 >,将持续为你更新...