JUnit 5 是 Java 生态中最流行的单元测试框架,由 JUnit Platform、JUnit Jupiter 和 JUnit Vintage 三个子项目组成。以下是 JUnit 5 的全面使用指南及示例:


一、环境配置

1. Maven 依赖
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.3</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.3</version>
    <scope>test</scope>
</dependency>
2. Gradle 依赖
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.3'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3'

二、核心注解

注解说明
@Test标记测试方法
@BeforeEach每个测试方法执行前运行
@AfterEach每个测试方法执行后运行
@BeforeAll所有测试方法执行前运行(静态方法)
@AfterAll所有测试方法执行后运行(静态方法)
@DisplayName自定义测试类或方法的显示名称
@Disabled禁用测试方法或类
@Nested定义嵌套测试类
示例
import org.junit.jupiter.api.*;

class CoreAnnotationsTest {

    @BeforeAll
    static void initAll() {
        System.out.println("初始化全局资源");
    }

    @BeforeEach
    void init() {
        System.out.println("初始化测试资源");
    }

    @Test
    @DisplayName("测试加法")
    void testAddition() {
        Assertions.assertEquals(4, 2 + 2);
    }

    @AfterEach
    void tearDown() {
        System.out.println("清理测试资源");
    }

    @AfterAll
    static void tearDownAll() {
        System.out.println("清理全局资源");
    }
}

三、断言(Assertions)

JUnit 5 提供丰富的断言方法:

1. 基本断言
@Test
void basicAssertions() {
    // 相等性断言
    Assertions.assertEquals(4, 2 + 2);
    
    // 布尔断言
    Assertions.assertTrue(5 > 3);
    Assertions.assertFalse(3 > 5);
    
    // 空值断言
    String str = null;
    Assertions.assertNull(str);
}
2. 组合断言(Grouped Assertions)
@Test
void groupedAssertions() {
    String name = "John";
    Assertions.assertAll("组合断言",
        () -> Assertions.assertEquals("John", name),
        () -> Assertions.assertTrue(name.startsWith("J"))
    );
}
3. 异常断言
@Test
void exceptionTesting() {
    Exception exception = Assertions.assertThrows(
        ArithmeticException.class,
        () -> { int result = 1 / 0; }
    );
    Assertions.assertEquals("/ by zero", exception.getMessage());
}

四、参数化测试

使用 @ParameterizedTest 和不同的参数来源。

1. 添加依赖
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.9.3</version>
    <scope>test</scope>
</dependency>
2. 示例
@ParameterizedTest
@ValueSource(ints = {1, 3, 5, 7})
void testOddNumbers(int number) {
    Assertions.assertTrue(number % 2 != 0);
}

@ParameterizedTest
@CsvSource({"2, 3, 5", "5, 5, 10"})
void testAddition(int a, int b, int expected) {
    Assertions.assertEquals(expected, a + b);
}

五、嵌套测试

使用 @Nested 组织测试类结构:

class NestedTest {
    @Nested
    class WhenNew {
        @Test
        void testInitialState() {
            Assertions.assertTrue(true);
        }
    }

    @Nested
    class AfterAction {
        @Test
        void testAfterAction() {
            Assertions.assertFalse(false);
        }
    }
}

六、动态测试

运行时生成测试用例:

@TestFactory
Stream<DynamicTest> dynamicTests() {
    return Stream.of(
        DynamicTest.dynamicTest("动态测试1", () -> Assertions.assertTrue(true)),
        DynamicTest.dynamicTest("动态测试2", () -> Assertions.assertEquals(4, 2 + 2))
    );
}

七、超时测试

@Test
@Timeout(1) // 1秒超时
void testTimeout() throws InterruptedException {
    Thread.sleep(500); // 测试通过
}

八、扩展模型(Extension)

通过 @ExtendWith 自定义扩展:

class MyExtension implements BeforeEachCallback {
    @Override
    public void beforeEach(ExtensionContext context) {
        System.out.println("自定义扩展逻辑");
    }
}

@ExtendWith(MyExtension.class)
class ExtensionTest {
    @Test
    void testWithExtension() {
        Assertions.assertTrue(true);
    }
}

九、测试生命周期

JUnit 5 生命周期顺序:

  1. @BeforeAll
  2. @BeforeEach
  3. @Test
  4. @AfterEach
  5. @AfterAll

十、测试执行顺序

默认顺序是随机的,可通过 @TestMethodOrder 指定顺序:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class OrderedTest {
    @Test
    @Order(1)
    void firstTest() {
        System.out.println("第一个测试");
    }

    @Test
    @Order(2)
    void secondTest() {
        System.out.println("第二个测试");
    }
}

总结

JUnit 5 提供了现代化的测试功能,包括参数化测试、动态测试、嵌套测试等。通过合理使用注解和断言,可以编写清晰、灵活的单元测试。更多高级用法可参考 JUnit 5 官方文档。

更多推荐