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

2023-11-18


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

生成的报告:





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Cobertura 统计多模块maven项目测试覆盖率 的相关文章

随机推荐

  • 三步在两台服务器间迁移conda环境

    引言 背景是我现在要跑的实验在一台服务器上跑有点来不及了 需要将conda环境和文件一起迁移到另一台服务器上 文件的迁移可以用scp或者rsync 但是conda虚拟环境的迁移则不行 步骤 step 1 将当前的虚拟幻境信息写入enviro
  • 制造业基本ERP管理系统模块全解析

    一 销售模块 1 成品分类 客户分类需要能做到多维统计 比如一个产品既属于成品又属于机架 还可以属于铝制品 成品和客户都必须能实现这种多维分类 相应报表也能根据这些多维分类进行分析统计 2 查看该销售订单时 可以直接查看到该张销售订单的执行
  • 最好不要过度处理EEG数据

    自动预处理方法对于处理大量公开可用的EEG 脑电图 数据库至关重要 但由于我们缺乏用于比较这些方法的数据质量指标 因此最佳方法仍然未知 在这里 我们设计了一个简单但稳健的EEG数据质量度量标准 用于评估两个实验条件之间在100毫秒刺激后时间
  • 报错为method does not override method from its superclass解决

    你要重写接口的方法就得让实现类实现接口 public class UserServiceImpl implements UserService 没有实现接口就加重写注解 Override 系统不知道重写了什么接口方法 肯定报错 建议巩固一下
  • 为什么函数y=f(x)的导数dy/dx可以适用分数运算呢?

    一 问题背景 在同济大学高等数学关于导数的内容中 如果函数y f x 可以由参数方程 表示 且三个函数皆可导 且x的值不为0 则 才开始看这个公式推导时 觉得没什么问题 仔细一想 dy dx是导数的表示符号 为什么这个符号可以适用分数运算公
  • Hive 视图和索引

    一 视图 1 1 简介 Hive 中的视图和 RDBMS 中视图的概念一致 都是一组数据的逻辑表示 本质上就是一条 SELECT 语句的结果集 视图是纯粹的逻辑对象 没有关联的存储 Hive 3 0 0 引入的物化视图除外 当查询引用视图时
  • Spring的Factories机制介绍

    项目场景 Spring的Factories机制介绍 Spring的Factories机制介绍
  • 如何使用vscode开发uniapp并运行

    如何使用vscode开发uniapp并运行 1 必须先下载HBuilderX然后导入你需要开发的uni项目 2 然后在vscode中再次打开你的uni项目 3 去vscode插件市场安装一个uni helper这个插件 4 即可在vscod
  • java 利用ganymed-ssh2 远程执行linux shell 命令

    早期的ganymed ssh2包也可以实现远程调研linux shell 命令 但是这个包最新版本是2014年之后 就没有更新了 发现linux 操作系统安装 open ssh 8 5及更高级版本 就一直提示连接失败 可以使用jsch 最新
  • linux内存利用率计算方式

    一 查看内存的方式 root vmware free h root vmware cat proc meminfo 需要使用的指标有 MemTotal MemFree Buffers Cached MemTotal 总内存大小 MemFre
  • 计算半圆弧的周长及半圆的面积

    3 计算半圆弧的周长及半圆的面积 编程并输出半径r 5 3的半圆弧长 提示 半圆弧长不应该加直径的长度 及该半圆弧与直经围成的半圆的面积 的取值为3 14159 要求半径r和必须利用宏常量表示 include
  • MacOS怎么查看进程占用内存是多少

    一 背景 在Linux下可以使用 free 命令来方便的查看内存占用情况 如 free g free m等 但MacOS下没有这个命令 既然如此 那么MacOS里是否有类似的工具呢 而我们又该如何查看整个PC的内存占用情况 及指定进程的内存
  • 慢慢欣赏linux pud_offset解析

    typedef struct pudval t pud pud t gt typedef u64 pudval t dir表示L0页表索引的指针 指向PUD页表的基地址 define pud offset dir addr pud t va
  • 《计算机工程》期刊 从投稿到录用过程

    本人 18级双一流院校全日制研究生在读 专业 地理学 研究方向 激光雷达数据处理与三维点云语义分割 文章投计算机工程期刊从投稿到可刊总周期 两个月之内 审稿费100元 可加急 发表情况 预计十月发表 期刊选择 论文修改完成之后 自己有上网了
  • 教你利用IBM的开发手册

    在IBM AIX下做开发的不少人一直都不知道IBM其实已经提供了详尽的开发文档及手册供开发人员使用 很多人仍然使用很原始的方式 例如在GOOGLE中搜索 或者买本手册型的书放在边上 更有甚者直接记在脑子里 这算是相当聪明的了 但是 有许多与
  • 山石发声

    技术变化快 投入不可控 攻击侧升级 攻防不对等 人才缺口大 维护成本高 山石网科安全运营体系 让安全运营挑战迎刃而解 近年来 全球安全服务市场景气度较高 行业增速远高于安全行业的整体水平 究其原因 首先是IT基础架构的变化驱动安全服务体系的
  • java每日一题:手动触发垃圾回收(GC)

    面试官 首先 我想问一下 你能向我解释一下 手动触发Java垃圾回收 的过程吗 面试者 在Java中 垃圾回收是自动进行的 由Java虚拟机 JVM 负责管理 但是 有时候我们可能希望手动触发垃圾回收以释放一些无用的对象 这可以通过调用Sy
  • Scrapy的基本介绍、安装及工作流程

    一 Scrapy介绍 Scrapy是什么 Scrapy 是用 Python 实现的一个为了爬取网站数据 提取结构性数据而编写的应用框架 异步爬虫框架 通常我们可以很简单的通过 Scrapy 框架实现一个爬虫 抓取指定网站的内容或图片 Scr
  • 程序员搜索技巧

    1 搜索时 一定使用关键字搜索 空格 浓缩减少废话与口语 不断负反馈增添修改关键词 再不行就英文 2 精确搜索 作为整体 用 双引号 3 查找标题含有的确定关键词 intitle 英文冒号 4 站内搜索 过滤垃圾广告 定位某一网址答案 xx
  • Cobertura 统计多模块maven项目测试覆盖率

    Cobertura 统计单元测试覆盖率的机制 运行类 并在一个log文件中记录哪一行被执行 然后将源代码和log文件进行比对 1 简单的情况 单模块maven项目 项目结构 源代码 src main java se sigma calcul