Mockito 提供两种方式配置方法的返回值:doReturn().when()
和 when().thenReturn()
。虽然它们功能相似,但行为差异显著,需根据具体场景选择使用。
1. 语法对比
方法 | 语法示例 |
---|---|
when().thenReturn() | when(mock.method()).thenReturn(value) |
doReturn().when() | doReturn(value).when(mock).method() |
2. 核心区别
特性 | when().thenReturn() | doReturn().when() |
---|---|---|
是否执行真实方法 | 执行真实方法(对 Spy 对象而言) | 不执行真实方法(直接覆盖行为) |
适用方法类型 | 非 void 方法 | 任意方法(包括 void 方法) |
异常处理 | 若真实方法抛异常,需先处理 | 安全跳过真实方法执行,避免异常 |
链式调用 | 支持 .thenReturn().thenThrow() | 需通过 doReturn().doThrow().when() 链式调用 |
3. 典型场景分析
场景 1:对 Spy 对象配置桩(避免执行真实方法)
问题:使用 when().thenReturn()
时,Spy 对象的真实方法会被执行。
示例:
List<String> realList = new ArrayList<>();
List<String> spyList = spy(realList);
// 错误:add("A") 会被实际执行,导致列表包含 "A"
when(spyList.add("A")).thenReturn(true);
// 正确:add("A") 不会执行
doReturn(true).when(spyList).add("A");
场景 2:Mock void 方法
问题:when()
无法直接用于 void 方法。
示例:
// 错误:语法不合法,因为 mockLogger.error() 是 void 方法
when(mockLogger.error(anyString())).thenReturn(...);
// 正确:使用 doNothing() 或 doReturn()
doNothing().when(mockLogger).error(anyString());
doReturn(true).when(mockLogger).error(anyString()); // 假设修改返回类型
场景 3:绕过异常方法
问题:真实方法可能抛出异常(如未初始化)。
示例:
public class Service {
public String getConfig() {
throw new RuntimeException("未初始化!");
}
}
Service spyService = spy(new Service());
// 错误:调用 getConfig() 抛出异常
when(spyService.getConfig()).thenReturn("default");
// 正确:跳过真实方法
doReturn("default").when(spyService).getConfig();
4. 链式调用对比
when().thenReturn()
链式调用
when(mockList.get(0))
.thenReturn("A") // 第一次调用返回 "A"
.thenReturn("B"); // 后续调用返回 "B"
doReturn().when()
链式调用
doReturn("A")
.doReturn("B")
.when(mockList).get(0);
5. 最佳实践
场景 | 推荐方法 | 理由 |
---|---|---|
普通 Mock 对象(非 Spy) | when().thenReturn() | 语法简洁,直观易读 |
Spy 对象或需跳过真实方法执行 | doReturn().when() | 避免副作用(如状态修改、异常抛出) |
Void 方法配置 | doNothing().when() | 唯一合法选择 |
多次调用不同返回值 | 均可,根据对象类型选择 | when() 更简洁,但需注意是否需执行真实方法 |
6. 总结
when().thenReturn()
:默认选择,适用于普通 Mock 对象的非 void 方法。doReturn().when()
:- 处理 Spy 对象,避免执行真实方法。
- 配置 void 方法 的返回值。
- 绕过可能抛出异常的真实方法调用。
正确选择方法可避免意外的副作用,提升测试的稳定性和可维护性。