Cobertura 统计多模块maven项目测试覆盖率


Cobertura 统计单元测试覆盖率的机制:运行类,并在一个log文件中记录哪一行被执行,然后将源代码和log文件进行比对。


1. 简单的情况:单模块maven项目

项目结构


源代码 src/main/java/se/sigma/calculator/Calculator.java

package se.sigma.calculator;

public class Calculator {
    public int nextFibonacci(int a, int b) {
        return a + b;
    }
}
单元测试 src/test/java/se/sigma/calculator/CalculatorTest.java

package se.sigma.calculator;

import org.junit.Test;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

public class CalculatorTest {

    @Test
    public void shouldCalculateFibonacci() {
        Calculator calculator = new Calculator();
        int expected = 13;
        int actual = calculator.nextFibonacci(5, 8);

        assertThat(actual, is(expected));
    }
}

我们添加maven cobetura插件

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>se.thinkcode</groupId>
    <artifactId>one-module-example</artifactId>
    <version>1.0</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>cobertura-maven-plugin</artifactId>
                <version>2.5.1</version>
                <executions>
                    <execution>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>cobertura</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
</project>
关键部分是 cobertura-maven-plugin,它在项目的process-classes阶段被执行,生成的报告如下所示



上图显示覆盖率是100%,两行代码都被执行到。代码没有分支,复杂度是1。

点击进入package se.sigma.calculator里面会得到如下结果图:


点击进入 Calculator 这个类会得到:


cobetura不仅会记录每行是否被执行到,还会记录每行被执行的次数(hits)。


2. 复杂的情况:多模块maven项目


在多模块项目中,我们往往会把源代码放在一个模块,测试代码放在另一个模块(出于项目分解管理或配置文件的原因)。而maven的模块是一个执行完再执行另一个,导致cobetura的代码覆盖率统计出现问题。

现有多模块项目结构如下:



      功能源代码放在product模块,单元测试代码放在test模块。java文件的内容和前面的一样。test模块添加了product模块的依赖,这样就可以import Calculator这个类。

根项目的pom.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>se.thinkcode</groupId>
    <artifactId>multi-module-failing-example</artifactId>
    <version>1.0</version>
    <packaging>pom</packaging>
    <modules>
        <module>product</module>
        <module>test</module>
    </modules>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>cobertura-maven-plugin</artifactId>
                <version>2.5.1</version>
                <executions>
                    <execution>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>cobertura</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
</project>

<modules>标签里包含它的两个模块 product 和test。同样加上了 cobertura-maven-plugin来生成测试覆盖率报告. 

product模块的pom.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>se.thinkcode</groupId>
        <artifactId>multi-module-failing-example</artifactId>
        <version>1.0</version>
    </parent>
    <groupId>se.thinkcode</groupId>
    <artifactId>calculator</artifactId>
    <version>1.0</version>
</project>

test模块的pom.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>se.thinkcode</groupId>
        <artifactId>multi-module-failing-example</artifactId>
        <version>1.0</version>
    </parent>
    <groupId>se.thinkcode</groupId>
    <artifactId>calculator-test</artifactId>
    <version>1.0</version>
    <dependencies>
        <dependency>
            <groupId>se.thinkcode</groupId>
            <artifactId>calculator</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>
</project>

依赖 product 的源代码,才能引用 Calculator并调用它的方法。

测试结果如下:


可以看到覆盖率是0,而我们知道正确的结果应该是100%。

点击进入package里面,显示Calculator.java没有被执行


点击进入Calculator.java里面,显示方法代码没有被执行


maven的项目结构是固定的,一个java模块生成一个target文件,各模块是隔离的,因此无法跨模块比对运行的测试类和源代码文件。这时我们想到另一种项目管理工具Ant。Ant与maven相比,它的灵活在于可以让用户自己指定源码的位置和编译后字节码的存放位置,如此又可以达到单模块maven项目的效果。

maven+Ant

在前面工程结构的基础上,我们在根目录加上Ant的 build.xml 文件。

multi-module-example
|-- build.xml
|-- pom.xml
|-- product
|   |-- pom.xml
|   `-- src
|       `-- main
|           `-- java
|               `-- se
|                   `-- sigma
|                       `-- calculator
|                           `-- Calculator.java
`-- test
    |-- pom.xml
    `-- src
        `-- test
            `-- java
                `-- se
                    `-- sigma
                        `-- calculator
                            `-- CalculatorTest.java

父项目根目录pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>se.thinkcode</groupId>
    <artifactId>multi-module-example</artifactId>
    <version>1.1</version>
    <packaging>pom</packaging>
    <modules>
        <module>product</module>
        <module>test</module>
    </modules>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-clean-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <filesets>
                        <fileset>
                            <directory>.</directory>
                            <includes>
                                <include>**/*.ser</include>
                            </includes>
                        </fileset>
                    </filesets>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
</project>

maven-clean-plugin是用来清楚之前生成的target文件(.ser结尾的是cobetura生成的报告)。这里不用再添加maven-cobetura插件,cobertura需要单独下载,在Ant 脚本中引用。

Cobertura.下载地址 http://cobertura.sourceforge.net/download.html 。我这里用的是Cobertura 1.9.4.1下载后解压到 /Users/tsu/java/cobertura-1.9.4.1 ,你可以修改成其他目录,但是要注意和 build.xml 中指定的路径一致。

Ant构建脚本build.xml:

<project>
    <target name="instrument">
        <!-- Add all modules that should be included below -->
        <!-- <antcall target="instrumentAModule">
            <param name="module" value="MODULE_NAME_TO_REPLACE"/>
        </antcall> -->
        <antcall target="instrumentAModule">
            <param name="module" value="product"/>
        </antcall>
    </target>

    <target name="report" depends="merge">
        <property name="src.dir" value="src/main/java/"/>
        <cobertura-report datafile="sum.ser"
                          format="html"
                          destdir="./target/report">
            <!-- Add all modules that should be included below -->
            <!-- fileset dir="./MODULE_NAME_TO_REPLACE/${src.dir}"/ -->
            <fileset dir="./product/${src.dir}"/>
        </cobertura-report>
    </target>

    <target name="merge">
        <cobertura-merge datafile="sum.ser">
            <fileset dir=".">
                <include name="**/cobertura.ser"/>
            </fileset>
        </cobertura-merge>
    </target>

    <target name="instrumentAModule">
        <property name="classes.dir" value="target/classes"/>
        <cobertura-instrument todir="./${module}/${classes.dir}">
            <fileset dir="./${module}/target/classes">
                <include name="**/*.class"/>
            </fileset>
        </cobertura-instrument>
    </target>

    <property environment="env"/>
    <property name="COBERTURA_HOME" value="/Users/tsu/java/cobertura-1.9.4.1"/>
    <property name="cobertura.dir" value="${COBERTURA_HOME}"/>
    <path id="cobertura.classpath">
        <fileset dir="${cobertura.dir}">
            <include name="cobertura.jar"/>
            <include name="lib/**/*.jar"/>
        </fileset>
    </path>
    <taskdef classpathref="cobertura.classpath" resource="tasks.properties"/>
</project>

两个重要的<targets>是:

  • instrument
  • report

instrument 用Cobertura instrumentation来执行编译类文件。

report 将执行的测试类和源代码组合起来,生成覆盖率报告。

product模块的pom.xml和之前一致 :

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>se.thinkcode</groupId>
        <artifactId>multi-module-example</artifactId>
        <version>1.1</version>
    </parent>
    <groupId>se.thinkcode</groupId>
    <artifactId>calculator</artifactId>
    <version>1.1</version>
</project>

test模块的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>se.thinkcode</groupId>
        <artifactId>multi-module-example</artifactId>
        <version>1.1</version>
    </parent>
    <groupId>se.thinkcode</groupId>
    <artifactId>calculator-test</artifactId>
    <version>1.1</version>
    <dependencies>
        <dependency>
            <groupId>se.thinkcode</groupId>
            <artifactId>calculator</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.cobertura</groupId>
            <artifactId>cobertura</artifactId>
            <version>1.9.4.1</version>
        </dependency>
    </dependencies>
</project>

test 模块需要添加 Cobertura依赖,这样在test phase才能记录执行的踪迹

项目的执行有以下四步:

  1. Compile all code
  2. Instrument the code
  3. Execute all tests
  4. Consolidate and build the report

即顺序执行下面的四条命令:

	mvn clean compile
	ant instrument
	mvn test
	ant report

生成的报告:





  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值