
JUnit 5 不仅是一个测试框架,更是一个平台。它被设计为模块化、可扩展的体系,从而能够很好地融入 Spring Boot 这类复杂框架中。理解其核心架构和运行机制,能帮助我们更好地编写测试。
🧱 一、架构概览:三个核心模块
JUnit 5 由三个核心子项目构成,实现了 “分层协作” 的架构:
JUnit Platform(平台):最底层的运行时基础设施。它定义了
TestEngineAPI(SPI),让 JUnit Jupiter、JUnit Vintage 等测试引擎可以接入。同时,它提供了LauncherAPI,供 IDE 和构建工具(如 Maven、Gradle)发现和执行测试。JUnit Jupiter(核心):JUnit 5 的编程模型和扩展模型,是我们编写测试时直接接触的部分。它包含
junit-jupiter-api(提供@Test、@BeforeEach等注解和断言)和junit-jupiter-engine(Jupiter 测试引擎的实现)。JUnit Vintage(兼容层):一个适配器,用于在 JUnit Platform 上运行 JUnit 3 和 JUnit 4 的旧测试用例,保障了兼容性。
⚙️ 二、核心工作流程:测试的生命周期
JUnit 5 执行测试主要分为两个阶段:
测试发现 (Test Discovery)
启动:IDE 或构建工具通过 JUnit Platform 的
LauncherAPI 发起测试请求。发现:
Launcher会向所有注册的TestEngine(如JupiterTestEngine)查询。构建:
TestEngine扫描 classpath,根据注解(如@Test)识别测试,并构建一个树形结构TestDescriptor来描述所有测试。测试执行 (Test Execution)
Launcher接收到TestDescriptor树后,开始执行。它会深度优先遍历这棵树,执行每个节点。
执行过程中的事件(如测试开始、成功、失败)会通过
EngineExecutionListener接口报告给Launcher。
TestDescriptor 树形结构示例
对于测试类 UserServiceTest,其 TestDescriptor 树形结构大致如下:
[Engine: junit-jupiter] // 根节点:Jupiter 测试引擎└── [Class: UserServiceTest] // 容器节点:测试类├── [Method: testCreateUser] // 叶子节点:测试方法└── [Method: testFindUser] // 叶子节点:测试方法
🎯 三、核心机制:扩展模型 (Extension Model)
JUnit 5 的扩展模型取代了 JUnit 4 中 Runner、Rule 等分散的扩展方式,提供了一套统一且强大的 SPI。
1. 如何注册扩展?
JUnit Jupiter 提供了三种注册扩展的方式:
声明式注册 (
@ExtendWith):最常用的方式,直接在测试类、方法或参数上声明。
@ExtendWith(SpringExtension.class) // 注册 Spring 扩展@SpringBootTestclassMyServiceTest{ /*...*/ }
编程式注册 (
@RegisterExtension):通过注解字段来注册,可以精细控制扩展的创建和配置。自动检测 (ServiceLoader):通过 Java 的
ServiceLoader机制自动发现并注册扩展。
2. 关键扩展点 (Extension Points)
扩展通过实现特定的接口来“监听”测试生命周期中的事件,从而介入执行流程。
生命周期回调:
BeforeAllCallback/AfterAllCallback:在所有测试之前/之后执行。BeforeEachCallback/AfterEachCallback:在每个测试方法之前/之后执行。TestInstancePostProcessor:在测试实例创建后对其进行后处理。参数解析 (
ParameterResolver):这是 Spring 测试集成的关键。SpringExtension通过实现ParameterResolver,使得测试方法参数能被自动注入。条件测试 (
ExecutionCondition):根据条件(如操作系统、环境变量)动态启用或禁用测试。异常处理 (
TestExecutionExceptionHandler):自定义测试方法抛出异常时的处理逻辑。
🌱 四、与 Spring Boot 的深度集成
Spring Boot 通过 spring-boot-starter-test 与 JUnit 5 无缝集成。
核心桥梁:
SpringExtension:这是 Spring 提供的 JUnit 5 扩展,它实现了BeforeAllCallback、TestInstancePostProcessor、ParameterResolver等多个扩展点,用于引导 Spring TestContext Framework,并在测试生命周期中管理 Spring 上下文。便捷注解:
@SpringBootTest、@WebMvcTest等注解本身都标记了@ExtendWith(SpringExtension.class),因此无需再手动添加。依赖注入与模拟:在测试中,可以像在业务代码中一样使用
@Autowired注入依赖,并使用@MockBean或@SpyBean来模拟或监视 Bean。
💎 总结
JUnit 5 的模块化架构、以 TestDescriptor 为核心的执行模型以及强大的扩展模型,使其成为一个现代且灵活的测试平台。Spring Boot 正是通过 SpringExtension 这个扩展,将自己强大的上下文管理能力无缝集成到 JUnit 5 的测试生命周期中,共同构成了 Spring Boot 的单元测试体系。
夜雨聆风