JUnit 4与JUnit 5的差异详解

概述

在进行SpringBoot项目单元测试时,发现有时候给类打上
@SpringBootTest注解就能运行项目,但有时候需要@RunWith(SpringRunner.class)@SpringBootTest注解才能运行,你有研究过这是为什么吗?本文就来讲一下这个问题。


Spring Boot中JUnit 4JUnit 5的差异详解

一、核心差异概述

特性 JUnit 4 JUnit 5
架构 单一JAR包 模块化设计(Jupiter, Vintage, Platform)
包结构 org.junit org.junit.jupiter.api
Spring Boot 2.x 默认集成 需手动配置
Spring Boot 3.x+ 需降级依赖 默认集成

二、依赖配置对比

1. Maven依赖

xml 复制代码
<!-- JUnit 4 典型依赖 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>

<!-- JUnit 5 典型依赖 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <scope>test</scope>
</dependency>

三、注解差异详解

1. 基础注解对照表

功能 JUnit 4 注解 JUnit 5 注解
测试方法 @Test @Test
前置初始化 @Before @BeforeEach
后置清理 @After @AfterEach
类级别初始化 @BeforeClass @BeforeAll
类级别清理 @AfterClass @AfterAll
禁用测试 @Ignore @Disabled

2. Spring集成测试

java 复制代码
// JUnit 4 写法
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
    // ...
}

// JUnit 5 写法(无需@RunWith)
@SpringBootTest
@ExtendWith(SpringExtension.class) // 可选(Spring Boot 2.1+自动配置)
public class UserServiceTest {
    // ...
}

四、断言与假设

1. 断言API对比

java 复制代码
// JUnit 4
import org.junit.Assert;
Assert.assertEquals(expected, actual);

// JUnit 5(支持Lambda表达式)
import org.junit.jupiter.api.Assertions;
Assertions.assertEquals(expected, actual, 
    () -> "自定义错误信息");

2. 链式断言(JUnit 5新增)

java 复制代码
assertAll("用户信息校验",
    () -> assertEquals("John", user.firstName()),
    () -> assertEquals("Doe", user.lastName())
);

五、兼容性与迁移方案

1. 混合测试支持

xml 复制代码
<!-- 在JUnit 5环境中运行JUnit 4测试 -->
<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
</dependency>

junit-vintage-engine是JUnit 5提供的一个兼容引擎,允许在JUnit 5环境中运行JUnit 3和JUnit 4的测试。这是为了帮助开发者在迁移到JUnit 5时,能够继续运行现有的JUnit 4(甚至JUnit 3)测试用例,而不需要立即重写所有测试代码。

作用和功能
  1. 兼容性支持:

    • junit-vintage-engine提供了一个运行时引擎,使得JUnit 4和JUnit 3的测试可以在JUnit 5的测试平台上运行。这对于拥有大量现有测试的项目特别有用,因为它允许逐步迁移到JUnit 5。
  2. 无缝集成:

    • 通过添加这个依赖,JUnit 5的测试运行器(如IDE内置的运行器或构建工具中的运行器)可以识别并执行使用旧版JUnit API编写的测试。
  3. 迁移过渡:

    • 在项目中同时使用JUnit 4和JUnit 5测试时,junit-vintage-engine可以作为一个过渡工具。你可以逐步将新的测试用例用JUnit 5编写,而旧的测试用例继续使用JUnit 4,直到有时间和资源进行全面迁移。
使用场景
  • 渐进式迁移 : 如果你的项目中已经有大量的JUnit 4测试,并且不可能一次性迁移到JUnit 5,junit-vintage-engine提供了一种渐进式迁移路径。
  • 遗留系统维护: 在维护遗留系统时,可能需要继续支持旧的JUnit测试框架,而新功能使用JUnit 5进行测试。
如何使用

在你的项目的构建文件中(如Maven的pom.xml),添加以下依赖:

xml 复制代码
<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
</dependency>
注意事项
  • 兼容性问题: 在某些情况下,JUnit 4和JUnit 5的注解和特性可能会冲突,因此在迁移过程中需要注意这些潜在问题。
  • 性能影响 : 虽然junit-vintage-engine提供了兼容性支持,但在某些情况下可能会引入额外的运行时开销。

通过使用junit-vintage-engine,开发者可以在不立即重写现有测试的情况下,享受JUnit 5的现代特性和改进的运行环境。这是一个非常有用的工具,特别是在大型项目的测试框架升级过程中。

2. 常见迁移问题

  • ❌ 错误:java.lang.NoClassDefFoundError: org/junit/runner/manipulation/Filter
  • ✅ 解决:检查是否同时存在junit4junit-jupiter依赖冲突

六、最佳实践建议

  1. 新项目 :Spring Boot 3.x+默认使用JUnit 5,无需额外配置
  2. 旧项目迁移
    • 逐步替换@Before/@After@BeforeEach/@AfterEach
    • 使用junit-vintage-engine保持向下兼容
  3. 特性升级 :利用JUnit 5@ParameterizedTest实现参数化测试

七、总结

JUnit 5在Spring Boot中的使用更加现代化,推荐新项目直接采用。对于历史项目,可通过渐进式迁移策略平稳过渡。关注Spring Boot版本与JUnit版本的对应关系,可有效避免兼容性问题。


附录 :Spring Boot版本与JUnit默认支持对照表

Spring Boot版本 默认JUnit版本
2.4.x及以下 JUnit 4
2.5.x+ JUnit 5
3.0.x+ JUnit 5

希望这篇对比分析能帮助您更好地在Spring Boot项目中运用单元测试!如果有具体使用场景的问题,欢迎在评论区交流讨论。

相关推荐
考虑考虑1 天前
Jpa使用union all
java·spring boot·后端
用户3721574261351 天前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊1 天前
Java学习第22天 - 云原生与容器化
java
渣哥1 天前
原来 Java 里线程安全集合有这么多种
java
间彧1 天前
Spring Boot集成Spring Security完整指南
java
间彧1 天前
Spring Secutiy基本原理及工作流程
java
Java水解1 天前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆1 天前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学1 天前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole1 天前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端