Appearance
单元测试中 Mock 的用法和写法,基本的内容可以问一下大模型。
基于 JUnit5,使用 MockitoExtension 和 @Mock,用于写单元测试。
- 注解
- Mock
- 用于创建某个类(或接口)的模拟对象(Mock Object)
- InjectMocks
- 用于标记被测试对象(即你想要测试的类)
- Mock
- 单测
- 调用 mock 方法时一定要提前用
when(...).thenReturn(...)或doReturn(...)等设置好期望行为,否则 mock 返回的都是 null 或默认值,容易导致 NullPointerException。
- 调用 mock 方法时一定要提前用
一般都是先 mock,然后调用方法
@Tag("serviceTest")
@ExtendWith(MockitoExtension.class)
public class SelfActivityAppServiceNewTest {
// === Core dependencies ===
@Mock
private SelfActivityService selfActivityService;
}如果使用大模型去写单测的时候,有时候建议还是手动微调一下, 有时候可能就是mock参数的问题(当然也有可能是提示词的问题),如果让大模型写,效果比预期可能差一些。
项目框架
SpringBoot,覆盖率使用的是 jacoco ,依赖管理使用的是 maven
单元测试写法
基本的一些用法
常用注解
| 注解 | 用途 |
|---|---|
| @Mock | 创建模拟对象,所有方法默认返回空值 |
| @InjectMocks | 创建真实对象,并注入所有@Mock对象作为依赖 |
| @BeforeEach | 每个测试方法执行前运行,用于初始化 |
| @SpringBootTest | 加载完整应用上下文的集成测试 |
| @WebMvcTest | 仅测试MVC控制器,加载相关Web层组件 |
| @DataJpaTest | 专门测试JPA组件 |
Mockito 基本用法
java
// 设置模拟行为
when(userRepository.findById(1L)).thenReturn(Optional.of(new User(1L, "张三")));
// 模拟任意参数
when(service.process(any())).thenReturn(result);
// 初始化Mocks (通常在@BeforeEach中)
MockitoAnnotations.openMocks(this);常用断言
java
// 非空检查
assertNotNull(result);
// 相等性检查
assertEquals(expected, actual);
assertEquals(3.14, value, 0.01); // 带容差的浮点数比较
// 布尔条件检查
assertTrue(condition);
assertFalse(list.isEmpty());
// 异常检查
assertThrows(IllegalArgumentException.class, () -> service.method(invalidArg));验证方法调用
java
// 验证方法被调用一次
verify(service).method(arg);
// 验证调用次数
verify(service, times(2)).method(any());
verify(service, never()).unusedMethod();
verify(service, atLeastOnce()).method();
// 验证无其他调用发生
verifyNoMoreInteractions(service, repository);
// 验证调用顺序
InOrder order = inOrder(service, repo);
order.verify(service).first();
order.verify(repo).second();测试模板
java
@ExtendWith(MockitoExtension.class)
class ServiceTest {
@Mock
private Repository repository;
@InjectMocks
private ServiceImpl service;
@BeforeEach
void setUp() {
// 初始化工作,设置通用mock行为
when(repository.findById(1L)).thenReturn(Optional.of(new Entity(1L)));
}
@Test
void testMethod_Scenario_ExpectedResult() {
// 准备
when(repository.specificMethod()).thenReturn(expectedValue);
// 执行
Result result = service.methodUnderTest(input);
// 验证
assertNotNull(result);
assertEquals(expected, result.getValue());
assertTrue(result.isValid());
// 行为验证
verify(repository).specificMethod();
verifyNoMoreInteractions(repository);
}
}最佳实践
- 单一职责:每个测试方法只测一个功能点
- 准备-执行-验证:遵循AAA模式(Arrange-Act-Assert)
- 测试边界条件:包括正常情况和异常情况
- 隔离依赖:使用@Mock隔离外部依赖
- 可读性优先:使用描述性命名和适当注释
- 断言在先,验证在后:先验证结果正确,再验证行为正确