JUnit4 和 JUnit5 的差异对比

JUnit5相比JUnit4进行了全面升级,采用模块化设计,新增动态测试、条件注解和扩展机制,提供更灵活的断言和更细粒度的测试控制,同时保持向下兼容性。
博客:https://www.emanjusaka.com
博客园:https://www.cnblogs.com/emanjusaka
公众号:emanjusaka的编程栈
by emanjusaka from https://www.emanjusaka.com/archives/junit4-junit5-difference 彼岸花开可奈何
本文为原创文章,可能会更新知识点以及修正文中的一些错误,全文转载请保留原文地址,避免产生因未即时修正导致的误导。
JUnit 是一个广泛使用的 Java 单元测试框架,可以帮助开发者编写可靠的单元测试,提升代码质量。通过注解和断言,测试代码简洁且易于维护。
Maven依赖
<!-- 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、架构不同
JUnit4 采用单一 JAR 包,功能集中缺乏模块化设计,扩展性有限。
JUnit5 是模块化设计包括Jupiter
、Vintage
、Platform
。
- Jupiter:提供新的编程模型和扩展机制
- Vintage:兼容 JUnit3 和 JUnit4 的测试
- Platform:测试引擎的基础设施
2、包结构不同
采用的包名也是不同的,JUnit4 的包名是org.junit
,JUnit5 的包名是org.junit.jupiter.api
。
3、注解变化
JUnit4 的常用注解:
@Test
@Before
/@After
@BeforeClass
/@AfterClass
@Ignore
JUnit5
-
注解变化:
-
@Before
->@BeforeEach
-
@After
->@AfterEach
-
@BeforeClass
->@BeforeAll
-
@AfterClass
->@AfterAll
-
@Ignore
->@Disabled
-
-
新增核心注解:
@DisplayName
:为测试类或方法设置自定义显示名称@Nested
:支持嵌套测试类,支持层次化测试结构@TestFactory
:标记动态测试工厂方法,返回DynamicTest
流@RepeatedTest
:替代JUnit4的循环测试,指定重复运行次数@ParameterizedTest
:参数化测试(需配合@ValueSource
等参数源使用)@Disabled
:替代JUnit4的@Ignore
,禁用测试类或方法
-
新增条件注解:
-
@EnabledOnOs/@DisabledOnOs
:根据操作系统条件执行(如@EnabledOnOs(OS.LINUX)
) -
@EnabledIfSystemProperty
:根据系统属性条件执行(如@EnabledIfSystemProperty(named="env", matches="dev")
) -
@EnabledIfEnvironmentVariable
:根据环境变量条件执行 -
@EnabledIf/@DisabledIf
:自定义脚本条件(如@EnabledIf("customCheck()")
)
-
4、断言机制
JUnit4:
断言方法在org.junit.Assert
类中
assertEquals(expected, actual);
assertTrue(condition);
JUnit5:
断言方法在org.junit.jupiter.api.Assertions
类中,新增了断言方法:
assertAll
:组合断言,确保所有断言都执行assertThrows
:验证是否抛出指定异常assertTimeout
:验证代码是否在指定时间内完成
// JUnit 4 断言示例
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class JUnit4AssertionExample {
@Test
public void testAssertion() {
int result = 2 + 2;
assertEquals(4, result);
}
}
// JUnit 5 断言示例
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class JUnit5AssertionExample {
@Test
public void testAssertion() {
int result = 2 + 2;
assertEquals(4, result, () -> "2 + 2 should equal 4");
}
}
5、动态测试
JUnit4 不支持动态测试,所有测试方法需在编译时确定。
JUnit5 支持动态测试,允许在运行时生成测试用例
import org.junit.jupiter.api.*;
import java.util.stream.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.DynamicTest.*;
class DynamicTestsExample {
@TestFactory
Stream<DynamicTest> dynamicTestsFromStream() {
return IntStream.range(1, 5)
.mapToObj(i -> dynamicTest(
"Test #" + i,
() -> assertTrue(i % 2 == 0, i + " 不是偶数")
));
}
}
6、兼容性差异
JUnit4 支持 Java8 以下的版本
JUnit5 需要 Java8+
7、扩展能力
JUnit5 新增的扩展机制(Extension API)通过模块化设计取代了 JUnit4 的 Runner
和 @Rule
机制,提供了更灵活、更精细的测试生命周期控制能力。
允许在测试的任意阶段(如测试前、后、异常处理等)插入自定义逻辑。对比 JUnit4 的 @Rule
只能作用于单个 Statement
。
JUnit5 日志扩展示例:
public class LoggingExtension implements
BeforeEachCallback, AfterEachCallback {
@Override
public void beforeEach(ExtensionContext context) {
System.out.println("Starting: " + context.getDisplayName());
}
@Override
public void afterEach(ExtensionContext context) {
System.out.println("Finished: " + context.getDisplayName());
}
}
// 使用扩展
@ExtendWith(LoggingExtension.class)
class MyTest {
@Test void test1() { ... }
}