【JUnit实战3_19】第十章:用 Maven 3 运行 JUnit 测试(下)

《JUnit in Action》全新第3版封面截图
写在前面
本篇继续梳理 Maven 知识点。本以为没什么可以复盘的,实测过程中却遇到了好几个不大不小的坑,一并记录下来,提醒自己不要自以为是,毕竟温故才能知新。
10.4 常用插件
从插件的角度看,Maven 也是一个通过运行插件来构建源代码的构建环境。Maven 构建中的每个任务都是由相应的插件来完成的。本节重点介绍了三个插件:maven-compiler-plugin、maven-surefire-plugin、maven-site-plugin,分别负责项目的编译、单元测试和项目文档生成。
另外,如果刚才的 Maven 项目骨架需要导入 Eclipse,Maven 也专门提供了一个 maven-eclipse-plugin 插件方便一键导入 Eclipse,无需手动安装,只要在创建好骨架后再运行 mvn eclipse:eclipse 即可。该插件会生成 Eclipse 识别项目需要的两个文件:.project 和 .classpath。
这是用最新版的 Eclipse(v2025-12 M1)导入 Maven 项目、并打开 pom.xml 后的实测截图:

踩坑备忘:慎用 Eclipse 的 exe 安装包
为了实测导入
Eclipse的效果,安装Eclipse时不小心下载了官方提供的.exe格式的安装包,结果又填错了Java 21的JRE路径(应该详细到bin目录),导致安装完成后软件能从GUI界面启动、但从快捷方式或安装目录双击eclipse.exe文件打开就报错(报错提示也很奇葩):
排查了很多地方,
jar包和里面的主类都是存在的,最后和老本本上的Eclipse仔细对比才找到根本原因:运行exe安装包时JRE路径不正确,导致最后的启动配置文件eclipse.ini缺了最关键的-vm参数。eclipse.ini前后对比如下(节选):# 更正前 -startup plugins/org.eclipse.equinox.launcher_1.7.0.v20250519-0528.jar# 更正后 -vm C:\Program Files\Java\jdk-21\bin -startup plugins/org.eclipse.equinox.launcher_1.7.0.v20250519-0528.jar时隔多年,
Eclipse官网已经将熟悉的zip包下载链接放在了很不起眼的位置,取而代之的时exe安装包:运行后可以优先从线上匹配最新的JDK和JRE版本,同时也方便插播硬广和捐款链接,可谓用心良苦……这个不大不小的坑也花了我大半个小时的宝贵时间,希望后来者能吸取教训。
10.4.1 编译器插件
即 maven-compiler-plugin 插件。每次运行 mvn compile 命令,其实就在调用该插件。编译前 Maven 还会经历一个验证阶段(对应命令 mvn validate),负责将 pom.xml 的依赖下载的本地,并引入项目的 classpath 中。而编译完成后的所有类文件则放入 target/classes/ 文件夹下。
该插件支持手动指定编译器支持的源代码版本,以及编译生成的字节码目标版本:
<build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins>
</build>
可以看到,插件在 pom.xml 中的声明和项目依赖很像,之所以省略 groupId 标签,是因为这是 Maven 的核心标签,groupId 默认均为 org.apache.maven.plugins,配置时可以不写。
10.4.2 单元测试插件
即 maven-surefire-plugin 插件,它是命令 mvn test 运行背后调用的插件,负责执行具体的单元测试(不仅限于 JUnit 单元测试)。通常在执行测试前,还会先执行一个 clean 命令(即 mvn clean test),以消除历史编译内容对本次测试的潜在干扰。
由于 Maven 的测试执行能力是由 maven-surefire-plugin 实现的,它通过生命周期绑定与 mvn test 命令关联。当项目的默认配置不符合预期时(如命名不规范等),很可能运行 mvn test 命令会自动跳过测试,此时就必须显式配置 maven-surefire-plugin 插件方可执行单元测试。
该插件也可以指定筛选条件,使得符合某种命名规范的测试用例才会最终执行。例如只执行后缀为 -Test.java 的测试用例:
<build><plugins><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.22.2</version><configuration><includes>**/*Test.java</includes></configuration></plugin></plugins>
</build>
更多手动配置详见 Maven 官方文档。
10.4.3 项目文档生成插件
即 maven-site-plugin 插件。该插件平时很少用到,但它可以根据配置自动生成项目文档,对应的命令是 mvn site,使用前需要先配置到 pom.xml:
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-site-plugin</artifactId><version>3.12.1</version>
</plugin>
mvn site 运行成功后会在 target/site/ 目录下生成该项目的文档,实测时的新版本较原书中的 3.7.1 版更加简洁规范(注意:以下截图效果必须先手动添加上面补充的 developers 等非必填标签):

10.4.4 生成单元测试报表
Maven 可以根据 JUnit 生成的 XML 格式的测试报表生成 HTML 格式的报表页。同理,该任务也是由一个名为 maven-surefire-report-plugin 插件完成的。虽然无需在 pom.xml 中单独声明,但由于 Maven 默认的构建阶段内,因此需要手动执行命令:
mvn surefire-report:report
最终会在 target/reports/ 文件夹中生成 HTML 格式的测试报表,其数据源是 JUnit 测试产生的原始格式(XML)报表,可以在 target/surefire-reports/ 下查看:

新版报表效果如下:

命令行和 IDE 在 Java 版本处理上的差异
实测发现,最新版的
pom.xml中指定的Java版本为 17:<maven.compiler.release>17</maven.compiler.release>导入
IDEA后项目结构自动选用我本机上的JDK21,运行报表生成命令一切正常;但是从命令行运行该命令就会严格按上述设置的 17 执行(本地未安装JDK17),于是运行报错:
根本原因:安装
JDK21时忘了同步更新JAVA_HOME的值,报错时还是JDK11所在的路径(太粗心)。另外,
Maven官方文档也推荐这种显式声明Java发行版本的写法,否则maven-compiler-plugin默认还是按Java 8处理。
10.5 Maven 构建的生命周期
Maven 有三个内置的生命周期:
default:用于生成项目构件(artifact);clean:用于清空项目构建产物;site:用于生成标准化的项目文档。
每个生命周期都由若干个阶段组成。一个相对完整的 Maven 默认生命周期如下图所示:

这里再次体现了 Maven 约定优于配置 的核心原则。Maven 会严格按照该顺序依次调用这些阶段,让它们依次执行。例如,执行 mvn compile 命令时,Maven 会先执行 Validate 验证阶段,然后再执行 Compile 阶段,完成项目源代码的编译工作。
10.6 实战演练:航班管理应用
本章的最后呼应“实战”主题,完整演示了如何利用 Maven 从零创建一个虚构的航班管理应用的全过程,其间还编写了一个单元测试,并最终将项目打包成 jar 文件、进而安装到本地 Maven 仓库。具体实战过程如下:
首先在 C:\junitbook\ 目录下打开命令行,运行以下 Maven 命令:
mvn archetype:generate -DgroupId=com.testeddatasystems.flights -DartifactId=flightsmanagement -DarchetypeArtifactid=maven-artifact-mojo
中途所有设置一律按默认设置执行,直接按回车键继续:

运行成功后,就得到一个 flightsmanagement 文件夹:

然后从 IDEA 导入该项目,效果如下:

删除默认的 App.java 及其测试类 AppTest.java,新增一个乘客实体类 Passenger.java:
package com.testeddatasystems.flights;public class Passenger {private String identifier;private String name;public Passenger(String identifier, String name) {this.identifier = identifier;this.name = name;}public String getIdentifier() {return identifier;}public String getName() {return name;}@Overridepublic String toString() {return "Passenger " + getName() +" with identifier: " + getIdentifier();}
}
然后将光标放到 Passenger 上,按 Ctrl + Shift + T 弹出新建单元测试的快捷窗口,按 Enter 继续后根据提示操作(测试类的名称都生成好了,只需按 Enter 确认)即可:


然后添加如下测试用例:
@Test
void testPassenger() {Passenger passenger = new Passenger("123-456-789", "John Smith");assertEquals("Passenger John Smith with identifier: 123-456-789",passenger.toString());
}
再从 Maven 侧边栏中执行命令 mvn clean install,将项目打包并安装到本地 Maven 仓库:

最终,target 目录下新增了一个名为 flightsmanagement-1.0-SNAPSHOT.jar 的 jar 文件;本地 Maven 库也多了一个对应的本地依赖:


小贴士
实战过程中尽量多用
IDEA的各种键盘操作,尽量少通过鼠标完成操作,以提高构建效率。


