JUnit4 和 JUnit5 的差异对比

本文发布于 2025年03月26日,阅读 28 次,点赞 1 次,归类于 Java
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 是模块化设计包括JupiterVintagePlatform

  • 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() { ... }
}
本篇完