1.JUnit 的导入
<dependencies>
<!-- JUnit Jupiter API + Engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
2.常用注解
注解 |
作用 |
|
声明一个测试方法 |
|
每个测试方法执行前执行 |
|
每个测试方法执行后执行 |
|
所有测试开始前执行(需 ) |
|
所有测试结束后执行(需 ) |
|
给测试类或方法自定义名称 |
|
禁用该测试方法 |
|
添加标签(分组执行测试用) |
3.常用断言
Assertions.assertEquals(expected, actual); // 相等
Assertions.assertNotEquals(a, b); // 不相等
Assertions.assertTrue(expression); // 断言为 true
Assertions.assertFalse(expression); // 断言为 false
Assertions.assertNull(obj); // 是 null
Assertions.assertNotNull(obj); // 不是 null
Assertions.assertThrows(ArithmeticException.class, () -> 1 / 0); // 异常断言
4.参数测试
基本注解:@ParameterizedTest
替代 @Test
,并结合不同的数据源注解,比如:
@ValueSource
:传入基础类型
@CsvSource
:传入多个参数(逗号分隔)
@MethodSource
:使用方法提供参数
@EnumSource
:枚举测试
@ArgumentsSource
:自定义参数源
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
// 枚举定义
enum Status {
NEW, IN_PROGRESS, DONE
}
public class ParameterizedTestExample {
// 1. @ValueSource 示例:基础类型参数(int / String / long / double)
@ParameterizedTest
@ValueSource(strings = {"hello", "junit", "test"})
@DisplayName("测试字符串长度为非空")
void testWithValueSource(String word) {
assertNotNull(word);
assertTrue(word.length() > 0);
}
// 2. @CsvSource 示例:多参数输入
@ParameterizedTest
@CsvSource({
"1, 2, 3",
"2, 3, 5",
"5, 7, 12"
})
@DisplayName("测试加法")
void testWithCsvSource(int a, int b, int expectedSum) {
assertEquals(expectedSum, a + b);
}
// 3. @MethodSource 示例:方法提供复杂参数(支持对象)
@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
@DisplayName("测试字符串是否为空白")
void testWithMethodSource(String input, boolean expected) {
assertEquals(expected, input == null || input.trim().isEmpty());
}
static Stream<Arguments> provideStringsForIsBlank() {
return Stream.of(
Arguments.of(" ", true),
Arguments.of("", true),
Arguments.of(null, true),
Arguments.of("abc", false)
);
}
// 4. @EnumSource 示例:遍历枚举值
@ParameterizedTest
@EnumSource(Status.class)
@DisplayName("测试所有状态枚举非空")
void testWithEnumSource(Status status) {
assertNotNull(status);
}
// 5. @ArgumentsSource 示例:自定义参数提供器
@ParameterizedTest
@ArgumentsSource(CustomStringProvider.class)
@DisplayName("使用自定义参数源")
void testWithArgumentsSource(String input) {
assertTrue(input.startsWith("arg"));
}
// 内部类:实现 ArgumentsProvider 接口
static class CustomStringProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of("arg1", "arg2", "arg3").map(Arguments::of);
}
}
}
5.实践例子
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
import java.util.Map;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@DisplayName("🧪 UserService CRUD 测试")
@Tag("user")
public class UserServiceTest {
private UserService userService;
@BeforeAll
static void beforeAll() {
System.out.println("🚀 启动 UserService 测试...");
}
@AfterAll
static void afterAll() {
System.out.println("✅ 所有测试已完成");
}
@BeforeEach
void setUp() {
userService = new UserService();
}
@AfterEach
void tearDown() {
System.out.println("--- 单个测试完成 ---");
}
@Test
@DisplayName("创建用户应返回ID并可查")
void testCreateAndGetUser() {
Long id = userService.createUser("Alice");
assertNotNull(id);
assertEquals("Alice", userService.getUser(id));
}
@Test
@DisplayName("删除用户成功后不能再获取")
void testDeleteUser() {
Long id = userService.createUser("Bob");
assertTrue(userService.deleteUser(id));
assertNull(userService.getUser(id));
}
@Test
@DisplayName("更新用户名称成功")
void testUpdateUser() {
Long id = userService.createUser("Charlie");
boolean updated = userService.updateUser(id, "Charles");
assertTrue(updated);
assertEquals("Charles", userService.getUser(id));
}
@Test
@DisplayName("获取所有用户")
void testListUsers() {
userService.createUser("Tom");
userService.createUser("Jerry");
Map<Long, String> users = userService.listUsers();
assertEquals(2, users.size());
assertTrue(users.containsValue("Tom"));
assertTrue(users.containsValue("Jerry"));
}
@Test
@DisplayName("创建空用户名应抛异常")
void testCreateUserWithNullName() {
assertThrows(IllegalArgumentException.class, () -> userService.createUser(" "));
}
// 🔁 参数化测试:@ValueSource
@ParameterizedTest
@ValueSource(strings = { "Alice", "Bob", "Charlie" })
@DisplayName("使用不同名称创建用户")
void testCreateWithValueSource(String name) {
Long id = userService.createUser(name);
assertNotNull(userService.getUser(id));
}
// 🔁 参数化测试:@CsvSource
@ParameterizedTest
@CsvSource({
"John, Johnny",
"Lucy, Lucille"
})
@DisplayName("创建并更新用户名")
void testUpdateWithCsvSource(String original, String updated) {
Long id = userService.createUser(original);
assertTrue(userService.updateUser(id, updated));
assertEquals(updated, userService.getUser(id));
}
// 🔁 参数化测试:@MethodSource
@ParameterizedTest
@MethodSource("provideUserNames")
@DisplayName("使用方法源批量创建用户")
void testCreateWithMethodSource(String name) {
Long id = userService.createUser(name);
assertNotNull(id);
assertEquals(name, userService.getUser(id));
}
static Stream<Arguments> provideUserNames() {
return Stream.of(
Arguments.of("Lily"),
Arguments.of("James"),
Arguments.of("Henry")
);
}
// 🔁 参数化测试:@EnumSource
@ParameterizedTest
@EnumSource(UserService.Role.class)
@DisplayName("枚举角色不为空")
void testWithEnumSource(UserService.Role role) {
assertNotNull(role);
}
// 🔁 参数化测试:@ArgumentsSource(自定义)
@ParameterizedTest
@ArgumentsSource(CustomNameProvider.class)
@DisplayName("使用自定义名字创建用户")
void testWithArgumentsSource(String name) {
Long id = userService.createUser(name);
assertTrue(userService.getUser(id).startsWith(name.substring(0, 1)));
}
static class CustomNameProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of("Alan", "Amy", "Ann").map(Arguments::of);
}
}
// 🚫 被禁用的测试
@Test
@Disabled("逻辑尚未实现")
void testFindUserByEmail() {
fail("该功能尚未开发");
}
}