| 模块 | 描述 |
|---|
| JUnit Platform | 测试框架基础平台 |
| JUnit Jupiter | 新编程模型和扩展模型 |
| JUnit Vintage | JUnit 3/4 兼容 |
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
| 注解 | 描述 |
|---|
@Test | 标记测试方法 |
@BeforeEach | 每个测试前执行 |
@AfterEach | 每个测试后执行 |
@BeforeAll | 所有测试前执行一次 |
@AfterAll | 所有测试后执行一次 |
@DisplayName | 测试显示名称 |
@Disabled | 禁用测试 |
@Nested | 嵌套测试类 |
@Tag | 标签过滤 |
@Timeout | 超时设置 |
import static org.junit.jupiter.api.Assertions.*;
@Test
void testAssertions() {
assertEquals(4, 2 + 2);
assertNotEquals(5, 2 + 2);
assertTrue(4 > 3);
assertFalse(4 < 3);
assertNull(null);
assertNotNull(new Object());
assertThrows(ArithmeticException.class, () -> {
int result = 1 / 0;
});
}
@Test
void testGroupedAssertions() {
assertAll("person",
() -> assertEquals("Alice", person.getName()),
() -> assertEquals(25, person.getAge()),
() -> assertEquals("alice@example.com", person.getEmail())
);
}
@Test
void testTimeout() {
assertTimeout(Duration.ofMillis(500), () -> {
Thread.sleep(200);
});
}
class LifecycleTest {
@BeforeAll
static void setupAll() {
System.out.println("Before all tests");
}
@BeforeEach
void setup() {
System.out.println("Before each test");
}
@Test
void test1() {
System.out.println("Test 1");
}
@Test
void test2() {
System.out.println("Test 2");
}
@AfterEach
void teardown() {
System.out.println("After each test");
}
@AfterAll
static void teardownAll() {
System.out.println("After all tests");
}
}
@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})
void testPositive(int number) {
assertTrue(number > 0);
}
@ParameterizedTest
@ValueSource(strings = {"hello", "world", "junit"})
void testNonEmpty(String str) {
assertFalse(str.isEmpty());
}
| 注解 | 描述 |
|---|
@ValueSource | 单类型值数组 |
@NullSource | null 值 |
@EmptySource | 空值 |
@EnumSource | 枚举值 |
@MethodSource | 工厂方法 |
@CsvSource | CSV 格式 |
@CsvFileSource | CSV 文件 |
@ParameterizedTest
@CsvSource({
"1, 1, 2",
"2, 3, 5",
"-1, 1, 0",
"0, 0, 0"
})
void testAdd(int a, int b, int expected) {
assertEquals(expected, Calculator.add(a, b));
}
@ParameterizedTest
@MethodSource("provideTestData")
void testWithMethodSource(String input, int expected) {
assertEquals(expected, input.length());
}
static Stream<Arguments> provideTestData() {
return Stream.of(
Arguments.of("hello", 5),
Arguments.of("world", 5),
Arguments.of("", 0)
);
}
@DisplayName("Stack tests")
class StackTest {
Stack<String> stack;
@BeforeEach
void createStack() {
stack = new Stack<>();
}
@Nested
@DisplayName("when new")
class WhenNew {
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Nested
@DisplayName("after pushing")
class AfterPushing {
@BeforeEach
void pushElement() {
stack.push("element");
}
@Test
@DisplayName("is not empty")
void isNotEmpty() {
assertFalse(stack.isEmpty());
}
}
}
}
public class LoggingExtension implements BeforeEachCallback, AfterEachCallback {
@Override
public void beforeEach(ExtensionContext context) {
System.out.println("Before: " + context.getDisplayName());
}
@Override
public void afterEach(ExtensionContext context) {
System.out.println("After: " + context.getDisplayName());
}
}
@ExtendWith(LoggingExtension.class)
class MyTest {
@Test
void test() { }
}
| 扩展 | 功能 |
|---|
| MockitoExtension | Mockito 集成 |
| SpringExtension | Spring 集成 |
| TempDirectory | 临时目录 |
| 实践 | 描述 |
|---|
| 命名规范 | *Test.java |
| DisplayName | 使用有意义的名称 |
| 单一断言 | 每个测试一个关注点 |
| 嵌套组织 | 按场景分组 |
| 参数化 | 减少重复代码 |
| 标签过滤 | @Tag("slow") |
| 超时保护 | @Timeout |