关于 junit-5-skill
面向 Java 开发者的 JUnit 5 测试技能,涵盖常见测试类型、Mockito 用法和生产级测试模式。
主要功能
- 01单元与集成测试指导
- 02参数化与嵌套测试
- 03Mockito 测试模式
- 04断言与生命周期参考
- 05Maven 和 Gradle 测试命令
适用场景
- 01编写 Java 单元测试
- 02使用 Mockito 测试服务
- 03构建参数化测试用例
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ lambdatest/ agent-skills --skill junit-5-skill安装后在 Claude Code 中输入/junit-5-skill确认已加载。
附带文件reference/advanced-patterns.mdreference/playbook.md
详细介绍
JUnit 5 测试技能
你是一名专注于 JUnit 5 测试的资深 Java 开发者。
步骤 1 — 测试类型
├─ "unit test", "assert" → Standard unit test
├─ "parameterized", "multiple inputs" → @ParameterizedTest
├─ "mock", "Mockito" → Unit test with Mockito
├─ "integration test", "Spring" → Read reference/spring-integration.md
└─ Default → Standard unit test
核心模式
基本测试
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
@DisplayName("Addition of two positive numbers")
void addPositiveNumbers() {
assertEquals(5, calculator.add(2, 3));
}
@Test
void divideByZero_throwsException() {
assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0));
}
@Test
void multipleAssertions() {
assertAll("calculator operations",
() -> assertEquals(4, calculator.add(2, 2)),
() -> assertEquals(0, calculator.subtract(2, 2)),
() -> assertEquals(6, calculator.multiply(2, 3))
);
}
}
断言参考
assertEquals(expected, actual);
assertNotEquals(unexpected, actual);
assertTrue(condition);
assertFalse(condition);
assertNull(object);
assertNotNull(object);
assertThrows(IllegalArgumentException.class, () -> service.process(null));
assertTimeout(Duration.ofSeconds(2), () -> service.longRunningOp());
assertAll("group",
() -> assertNotNull(user.getName()),
() -> assertTrue(user.getAge() > 0)
);
assertIterableEquals(List.of(1, 2, 3), actualList);
参数化测试
@ParameterizedTest
@ValueSource(strings = {"hello", "world", "junit"})
void stringIsNotEmpty(String value) {
assertFalse(value.isEmpty());
}
@ParameterizedTest
@CsvSource({"1,1,2", "2,3,5", "10,-5,5"})
void addNumbers(int a, int b, int expected) {
assertEquals(expected, calculator.add(a, b));
}
@ParameterizedTest
@MethodSource("provideUsers")
void validateUser(String name, int age, boolean expected) {
assertEquals(expected, validator.isValid(name, age));
}
static Stream<Arguments> provideUsers() {
return Stream.of(
Arguments.of("Alice", 25, true),
Arguments.of("", 25, false),
Arguments.of("Bob", -1, false)
);
}
@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {" ", "\t"})
void blankStringsAreInvalid(String input) {
assertFalse(validator.isValid(input));
}
使用 Mockito 进行模拟
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock private UserRepository userRepo;
@Mock private EmailService emailService;
@InjectMocks private UserService userService;
@Test
void createUser_savesAndSendsEmail() {
User user = new User("[email protected]", "Alice");
when(userRepo.save(any(User.class))).thenReturn(user);
User result = userService.createUser("[email protected]", "Alice");
assertNotNull(result);
verify(userRepo).save(any(User.class));
verify(emailService).sendWelcomeEmail("[email protected]");
}
@Test
void getUser_notFound_throwsException() {
when(userRepo.findById(99L)).thenReturn(Optional.empty());
assertThrows(UserNotFoundException.class, () -> userService.getUser(99L));
}
}
嵌套测试
@DisplayName("UserService")
class UserServiceTest {
@Nested
@DisplayName("when creating a user")
class CreateUser {
@Test void withValidData_succeeds() { }
@Test void withDuplicateEmail_throwsException() { }
}
@Nested
@DisplayName("when deleting a user")
class DeleteUser {
@Test void existingUser_removesFromDb() { }
@Test void nonExistentUser_throwsException() { }
}
}
反模式
| 不推荐 | 推荐 | 原因 |
|---|---|---|
@Test public void test1() | @Test void shouldCalculateSum() | 名称具有描述性 |
| 测试私有方法 | 通过公共 API 测试 | 实现细节 |
| 不使用 @DisplayName | 始终添加显示名称 | 报告更清晰 |
assertEquals(true, x) | assertTrue(x) | 可读性更好 |
Maven 依赖项
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.14.0</version>
<scope>test</scope>
</dependency>
快速参考
| 任务 | 命令 |
|---|---|
| 运行全部测试 | mvn test 或 ./gradlew test |
| 运行测试类 | mvn test -Dtest=UserServiceTest |
| 运行测试方法 | mvn test -Dtest=UserServiceTest#createUser_succeeds |
| 运行带标签的测试 | @Tag("slow") + mvn test -Dgroups="slow" |
| 禁用 | @Disabled("Reason") |
| 条件执行 | @EnabledOnOs(OS.LINUX) |
| 超时 | @Timeout(value = 5, unit = TimeUnit.SECONDS) |
| 重复执行 | @RepeatedTest(5) |
| 排序 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) |
深入模式
生产级模式请参阅 reference/playbook.md:
| 章节 | 内容 |
|---|---|
| §1 项目设置 | Maven 依赖项、并行配置、surefire |
| §2 测试生命周期 | BeforeAll/Each、排序、标签 |
| §3 参数化 | CsvSource、MethodSource、EnumSource、ValueSource |
| §4 Mockito | @Mock/@InjectMocks、捕获器、验证顺序 |
| §5 嵌套与动态测试 | @Nested 分组、@TestFactory |
| §6 AssertJ | 流式断言、提取、集合检查 |
| §7 条件执行 | @EnabledOnOs、假设、@EnabledIf |
| §8 自定义扩展 | 计时、重试、BeforeTestExecution |
| §9 CI/CD | 使用测试报告器的 GitHub Actions |
| §10 调试表 | 8 个常见问题及其解决方法 |
| §11 最佳实践 | 12 项生产检查清单 |
评论
支持 Markdown