乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 介绍与核心概念

    • Maven是什么
    • 约定优于配置
  • 第2章 安装与配置

    • 安装与验证
    • settings.xml
    • 本地仓库与镜像
  • 第3章 POM与项目坐标

    • POM
    • GAV坐标
    • packaging
  • 第4章 标准目录布局

    • 标准目录布局
  • 第5章 依赖机制

    • dependencies
    • scope
    • 依赖传递
    • 依赖冲突与调解
    • exclusions
    • optional
    • dependencyManagement
  • 第6章 仓库

    • 仓库体系
    • 本地仓库
    • 远程仓库与镜像
    • 私服
  • 第7章 构建生命周期

    • 生命周期概述
    • clean 生命周期
    • default 生命周期
    • site 生命周期
    • 生命周期与插件绑定
  • 第8章 插件

    • 插件概述
    • maven-compiler-plugin
    • maven-surefire-plugin
    • maven-war-plugin
  • 第9章 继承与聚合

    • parent继承
    • 聚合
    • BOM
    • properties
  • 第10章 属性与资源过滤

    • 资源过滤
    • Profile
  • 第11章 常用命令

    • mvn compile
    • mvn test
    • mvn package
    • mvn clean
    • mvn install
    • mvn dependency:tree
  • 第12章 常见问题与最佳实践

    • 依赖冲突排查
    • 最佳实践

maven-surefire-plugin

本章承接 maven-compiler-plugin,讲解构建流程的下一环:测试。maven-surefire-plugin 是 Maven 的测试执行引擎,负责在编译完成后自动运行单元测试。理解它的执行时机和报告机制,是搭建 CI/CD 流水线的必备知识。


核心机制

理解 Surefire 需要把握两个关键点:

  1. test phase:Surefire 绑定在 test 生命周期阶段,不是 compile,也不是 package
  2. unit tests:Surefire 主要执行单元测试(通常指 JUnit、TestNG 等框架编写的测试),集成测试由 maven-failsafe-plugin 负责

Surefire 在生命周期中的位置

Surefire 插件绑定在 test 阶段,而 test 阶段位于生命周期中的这个位置:

validate → initialize → compile → test-compile → test → package → verify → install → deploy
                              ↑
                         Surefire 在这里执行

这意味着:

  • 必须先完成 compile(主代码编译)和 test-compile(测试代码编译)
  • 如果编译失败,Surefire 不会执行
  • 如果测试失败,默认情况下 package 及后续阶段不会执行(构建中断)

测试执行流程

Surefire 的执行流程可以概括为:

  1. 扫描:在 target/test-classes 中扫描符合命名规范的测试类
  2. 加载:通过反射加载测试类,识别 @Test 注解的方法
  3. 执行:调用 JUnit/TestNG 框架运行测试方法
  4. 报告:生成 XML 和 HTML 格式的测试报告到 target/surefire-reports

测试类命名规范

Surefire 默认只识别符合以下模式的类:

模式示例
*Test.javaEmployeeServiceTest.java
Test*.javaTestEmployeeService.java(不推荐)
*TestCase.javaEmployeeServiceTestCase.java

注意:Abstract*Test.java 默认会被跳过,因为 Surefire 认为抽象类不是可执行的测试。

生活类比:工厂质检员

想象 Maven 构建是一家食品工厂的生产线:

  • compile 阶段 = 原料加工,把面粉做成饼干胚
  • test 阶段 = 质检员(Surefire)抽检饼干
  • package 阶段 = 把通过质检的饼干装袋

Surefire 这位质检员的工作规则是:

  1. 只检查本批次的饼干(本次编译生成的测试类)
  2. 如果发现发霉的饼干(测试失败),立即拉响警报,停止整条生产线(构建失败)
  3. 每天下班前写一份质检报告(surefire-reports),记录抽检数量和不合格品数量

图示

上图展示了 Surefire 在生命周期中的关键位置:编译完成后、打包之前。测试通过,构建继续;测试失败,构建中断。这个设计确保了"有问题的代码不会被打包",是 Maven 保障代码质量的核心机制。


完整示例

场景

飞翔科技的 employee-system 项目新增了员工信息校验逻辑。后端小崔写了一个 EmployeeValidator 类,并配套编写了 JUnit 5 单元测试。架构师白歌要求:任何测试失败的代码都不能进入打包阶段。

操作前:项目状态

pom.xml 已声明 JUnit 5 依赖:

<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

src/test/java/com/feixiang/employee/EmployeeValidatorTest.java:

package com.feixiang.employee;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class EmployeeValidatorTest {

    @Test
    void shouldRejectEmptyName() {
        EmployeeValidator validator = new EmployeeValidator();
        assertFalse(validator.isValid(new Employee("", 5000)));
    }

    @Test
    void shouldAcceptValidName() {
        EmployeeValidator validator = new EmployeeValidator();
        assertTrue(validator.isValid(new Employee("张三", 5000)));
    }
}

操作步骤:执行测试

小崔运行完整构建:

$ mvn clean test

操作结果:测试通过

[INFO] --- maven-surefire-plugin:3.0.0-M9:test (default-test) @ employee-system ---
[INFO] Running com.feixiang.employee.EmployeeValidatorTest
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.045 s
[INFO] 
[INFO] Results :
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

查看生成的测试报告:

$ ls target/surefire-reports/
com.feixiang.employee.EmployeeValidatorTest.txt
TEST-com.feixiang.employee.EmployeeValidatorTest.xml

XML 报告片段(可被 Jenkins 等 CI 工具解析):

<testsuite name="com.feixiang.employee.EmployeeValidatorTest" tests="2" failures="0" errors="0" skipped="0" time="0.045">
  <testcase name="shouldRejectEmptyName" classname="com.feixiang.employee.EmployeeValidatorTest" time="0.021"/>
  <testcase name="shouldAcceptValidName" classname="com.feixiang.employee.EmployeeValidatorTest" time="0.018"/>
</testsuite>

反例:测试失败阻断构建

小崔不小心改坏了校验逻辑,导致 shouldRejectEmptyName 测试失败。再次运行:

$ mvn clean test
[INFO] --- maven-surefire-plugin:3.0.0-M9:test (default-test) @ employee-system ---
[INFO] Running com.feixiang.employee.EmployeeValidatorTest
[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
[ERROR] com.feixiang.employee.EmployeeValidatorTest.shouldRejectEmptyName -- Time elapsed: 0.012 s <<< FAILURE!
[ERROR] expected: <false> but was: <true>
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[ERROR] There are test failures.

变化分析:

  • 测试失败后,Maven 直接输出 BUILD FAILURE,不会继续执行 package 阶段
  • 李眉的 Jenkins 流水线捕获到构建失败,自动阻止了问题代码的部署
  • 黄俪的前端代码虽然不受影响,但整个项目的构建产物不会生成,确保了"有问题的后端代码不会流入生产环境"

易错点与常见问题

误区一:测试类命名不规范,Surefire 直接跳过

错误示例:把测试类命名为 EmployeeTestCase.java 以外的名字,如 EmployeeTests.java(某些旧版本 Surefire 不识别)或 TestEmployee.java(虽然识别,但不符合约定)。

纠正:严格遵循 *Test.java 命名规范。如果确实需要自定义测试类名模式,可以在 pom.xml 中配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M9</version>
    <configuration>
        <includes>
            <include>**/*Tests.java</include>
        </includes>
    </configuration>
</plugin>

误区二:JUnit 依赖的 scope 不是 test

错误配置:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.9.2</version>
    <!-- 漏写了 <scope>test</scope> -->
</dependency>

后果:JUnit 框架会被打包进最终的 JAR/WAR,污染生产环境。JUnit 只在编译和运行测试时需要,绝对不应该出现在生产产物中。

误区三:用 mvn package -DskipTests 跳过测试成为习惯

错误认知:"测试太慢了,我每次打包都加 -DskipTests,反正代码是我写的,不会有问题。"

纠正:-DskipTests 是应急手段(如紧急热修复),不是日常开发习惯。长期跳过测试会导致:

  1. 代码质量持续下降,回归 Bug 增多
  2. CI/CD 流水线失去意义(如果流水线也配了 skipTests)
  3. 新成员小崔修改代码时,不知道是否破坏了原有逻辑

正确做法:日常开发让 Surefire 正常工作;确实需要跳过测试时,明确记录原因并在任务完成后恢复。


小结

maven-surefire-plugin 是 Maven 构建流程中的"质检员",它在 test 阶段自动执行单元测试,测试通过则构建继续,测试失败则构建中断。通过生成 XML/HTML 测试报告,它为 CI/CD 流水线提供了可解析的质量数据。遵循测试类命名规范、确保测试依赖的 scope 为 test、不滥用跳过测试参数,是使用 Surefire 的三大最佳实践。

本章与全局的关系:本章讲解了编译后的测试执行环节。下一节将讲解 maven-war-plugin,它负责把通过测试的代码打包为 Web 应用部署包。

上一页
maven-compiler-plugin
下一页
maven-war-plugin