Skip to content

JUnit 5 是一个强大且灵活的测试框架,它支持多种功能,比如注解、参数化测试、生命周期管理、条件化测试等。以下是一些经典的 JUnit 5 使用案例,涵盖了不同的测试场景:

1. 基础的单元测试

最常见的单元测试用例是验证方法的正确性。可以使用 @Test 注解来标记测试方法。

java
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class CalculatorTest {

    @Test
    void testAdd() {
        Calculator calculator = new Calculator();
        assertEquals(5, calculator.add(2, 3));
    }

    @Test
    void testSubtract() {
        Calculator calculator = new Calculator();
        assertEquals(1, calculator.subtract(3, 2));
    }
}
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class CalculatorTest {

    @Test
    void testAdd() {
        Calculator calculator = new Calculator();
        assertEquals(5, calculator.add(2, 3));
    }

    @Test
    void testSubtract() {
        Calculator calculator = new Calculator();
        assertEquals(1, calculator.subtract(3, 2));
    }
}

2. 前置和后置处理(@BeforeAll 和 @BeforeEach)

@BeforeAll@BeforeEach 是生命周期管理注解,用于设置和清理测试前后的一些工作。

  • @BeforeAll:在所有测试方法之前执行一次(静态方法)。
  • @BeforeEach:在每个测试方法之前执行。
java
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class LifecycleTest {

    @BeforeAll
    static void setupBeforeAll() {
        System.out.println("Executed before all tests.");
    }

    @BeforeEach
    void setupBeforeEach() {
        System.out.println("Executed before each test.");
    }

    @Test
    void test1() {
        System.out.println("Running test1");
    }

    @Test
    void test2() {
        System.out.println("Running test2");
    }
}
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class LifecycleTest {

    @BeforeAll
    static void setupBeforeAll() {
        System.out.println("Executed before all tests.");
    }

    @BeforeEach
    void setupBeforeEach() {
        System.out.println("Executed before each test.");
    }

    @Test
    void test1() {
        System.out.println("Running test1");
    }

    @Test
    void test2() {
        System.out.println("Running test2");
    }
}

3. 条件化测试(@EnabledIf 和 @DisabledIf)

JUnit 5 支持条件化执行测试。可以基于一些条件(例如操作系统、JVM版本、系统环境变量等)启用或禁用测试。

java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;

class ConditionalTest {

    @Test
    @EnabledOnOs(OS.WINDOWS)
    void testOnlyOnWindows() {
        System.out.println("This test runs only on Windows OS.");
    }

    @Test
    @EnabledOnOs(OS.LINUX)
    void testOnlyOnLinux() {
        System.out.println("This test runs only on Linux OS.");
    }
}
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;

class ConditionalTest {

    @Test
    @EnabledOnOs(OS.WINDOWS)
    void testOnlyOnWindows() {
        System.out.println("This test runs only on Windows OS.");
    }

    @Test
    @EnabledOnOs(OS.LINUX)
    void testOnlyOnLinux() {
        System.out.println("This test runs only on Linux OS.");
    }
}

4. 参数化测试(@ParameterizedTest)

参数化测试使得同一个测试方法可以多次运行,每次使用不同的参数值。

java
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.ParameterizedTest;
import org.junit.jupiter.api.ValueSource;

class ParameterizedTestExample {

    @ParameterizedTest
    @ValueSource(ints = {1, 2, 3, 4, 5})
    void testIsPositive(int number) {
        assertTrue(number > 0);
    }
}
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.ParameterizedTest;
import org.junit.jupiter.api.ValueSource;

class ParameterizedTestExample {

    @ParameterizedTest
    @ValueSource(ints = {1, 2, 3, 4, 5})
    void testIsPositive(int number) {
        assertTrue(number > 0);
    }
}

使用 @ValueSource 来提供多个值并自动执行多次测试。可以用 @CsvSource@MethodSource 来提供更复杂的数据源。

5. 异常测试(@Test + assertThrows)

assertThrows 来验证方法是否抛出预期的异常。

java
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class ExceptionTest {

    @Test
    void testException() {
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
            throw new IllegalArgumentException("Invalid argument");
        });
        assertEquals("Invalid argument", exception.getMessage());
    }
}
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class ExceptionTest {

    @Test
    void testException() {
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
            throw new IllegalArgumentException("Invalid argument");
        });
        assertEquals("Invalid argument", exception.getMessage());
    }
}

6. 组合多个条件的测试(@Test + @Tag)

@Tag 可以用来标记测试,并按标签选择运行特定的测试。

java
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

class TagTest {

    @Test
    @Tag("fast")
    void testFast() {
        System.out.println("This is a fast test.");
    }

    @Test
    @Tag("slow")
    void testSlow() {
        System.out.println("This is a slow test.");
    }
}
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

class TagTest {

    @Test
    @Tag("fast")
    void testFast() {
        System.out.println("This is a fast test.");
    }

    @Test
    @Tag("slow")
    void testSlow() {
        System.out.println("This is a slow test.");
    }
}

使用 @Tag 标签,可以在运行时通过命令行参数指定运行的测试类型。例如,@Tag("fast") 只运行快速测试。

7. 测试类级别的前置和后置处理(@BeforeAll 和 @AfterAll)

@AfterAll 注解用于在所有测试方法执行完后进行清理工作。

java
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

class AfterAllTest {

    @BeforeAll
    static void setup() {
        System.out.println("Executed before all tests.");
    }

    @AfterAll
    static void cleanup() {
        System.out.println("Executed after all tests.");
    }

    @Test
    void test1() {
        System.out.println("Running test1");
    }

    @Test
    void test2() {
        System.out.println("Running test2");
    }
}
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

class AfterAllTest {

    @BeforeAll
    static void setup() {
        System.out.println("Executed before all tests.");
    }

    @AfterAll
    static void cleanup() {
        System.out.println("Executed after all tests.");
    }

    @Test
    void test1() {
        System.out.println("Running test1");
    }

    @Test
    void test2() {
        System.out.println("Running test2");
    }
}

8. 使用 assertAll 进行组合断言

assertAll 用于同时检查多个断言,而不是只关注第一个失败的断言。

java
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class AssertAllTest {

    @Test
    void testMultipleAssertions() {
        assertAll("Test all assertions",
            () -> assertEquals(4, 2 + 2),
            () -> assertTrue(5 > 3),
            () -> assertNotNull("Hello")
        );
    }
}
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class AssertAllTest {

    @Test
    void testMultipleAssertions() {
        assertAll("Test all assertions",
            () -> assertEquals(4, 2 + 2),
            () -> assertTrue(5 > 3),
            () -> assertNotNull("Hello")
        );
    }
}

9. 测试实例生命周期(@TestInstance)

JUnit 5 允许改变测试类的生命周期,默认是 PER_METHOD(每个测试方法创建新的实例)。如果你希望测试类的生命周期是 PER_CLASS,可以使用 @TestInstance(Lifecycle.PER_CLASS)

java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestInstanceLifecycle {

    private int count = 0;

    @Test
    void testCount1() {
        count++;
        System.out.println("Count: " + count);
    }

    @Test
    void testCount2() {
        count++;
        System.out.println("Count: " + count);
    }
}
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestInstanceLifecycle {

    private int count = 0;

    @Test
    void testCount1() {
        count++;
        System.out.println("Count: " + count);
    }

    @Test
    void testCount2() {
        count++;
        System.out.println("Count: " + count);
    }
}

10. 自定义扩展(@ExtendWith)

JUnit 5 允许你创建自定义扩展来在测试生命周期的特定点插入行为。以下是一个使用 @ExtendWith 注解的简单示例:

java
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.Test;

@ExtendWith(MyExtension.class)
class MyTest {

    @Test
    void test() {
        System.out.println("Test is running with custom extension.");
    }
}

class MyExtension implements TestExecutionExceptionHandler {
    @Override
    public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
        System.out.println("Handling exception in test: " + throwable.getMessage());
    }
}
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.Test;

@ExtendWith(MyExtension.class)
class MyTest {

    @Test
    void test() {
        System.out.println("Test is running with custom extension.");
    }
}

class MyExtension implements TestExecutionExceptionHandler {
    @Override
    public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
        System.out.println("Handling exception in test: " + throwable.getMessage());
    }
}

总结

这些是 JUnit 5 中常见的一些使用案例,涵盖了测试生命周期管理、参数化测试、条件化测试、异常处理、标签化测试、组合断言等不同方面。根据不同的应用场景,可以灵活使用这些功能来提升测试的质量和可维护性。