Java单元测试编写指南(基于JUnit和Mockito)
编写高质量单元测试的专业指南,基于JUnit 5和Mockito框架。
方法名_测试场景_期望结果每个测试用例应遵循Arrange-Act-Assert三段式结构:
@Test
void calculateTotal_withValidItems_returnsCorrectSum() {
// Arrange - 准备测试数据和依赖
List<Item> items = Arrays.asList(
new Item("A", 10.0),
new Item("B", 20.0)
);
Calculator calculator = new Calculator();
// Act - 执行被测试的方法
double result = calculator.calculateTotal(items);
// Assert - 验证结果是否符合期望
assertEquals(30.0, result, 0.001);
}
assertEquals(expected, actual) - 验证相等性assertNotNull(actual) - 验证非空assertTrue(condition) / assertFalse(condition) - 验证布尔条件assertThrows(Exception.class, () -> {...}) - 验证异常抛出assertAll() - 批量断言,全部执行assertTimeout(duration, () -> {...}) - 验证执行时间assertThat(result)
.isNotNull()
.isInstanceOf(User.class)
.extracting(User::getName)
.isEqualTo("张三");
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void getUser_whenExists_returnsUser() {
// 定义Mock行为
when(userRepository.findById(1L))
.thenReturn(Optional.of(new User("张三")));
// 执行测试
User user = userService.getUser(1L);
// 验证结果
assertEquals("张三", user.getName());
// 验证方法调用
verify(userRepository).findById(1L);
}
}
@Mock注解标记依赖@InjectMocks自动注入Mock对象when().thenReturn()定义Mock返回值verify()验证方法是否被调用any()、eq()等匹配器灵活匹配参数必须测试的边界条件:
每个public方法至少包含以下测试:
❌ 测试私有方法(应该测试public接口) ❌ 测试第三方库(应该Mock掉) ❌ 测试getter/setter(没有必要) ❌ 过度Mock(导致测试脆弱) ❌ 忽略异常测试
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer