应mock运行时实际被调用的对象,即接口而非实现类;因Java多态依赖实际类型,Mockito.when只对具体mock实例生效,故推荐直接@Mock接口并stub其方法。

在 Java 多态场景下用 Mockito.when 模拟接口方法,关键不是“能不能模拟”,而是“要 mock 哪个实例”——必须 mock 运行时实际被调用的对象,而不是声明类型。
明确多态调用的真实目标
Java 多态靠的是运行时对象的实际类型(而非引用类型)决定方法调用。Mockito 的 when() 只对具体 mock 对象生效,不能跨类型自动代理。
- 如果代码中使用 接口引用指向实现类实例(如
Service service = new UserService();),应 mock 该实现类实例,或更推荐:mock 接口本身(因接口可直接 mock) - 如果依赖通过 Spring 注入(如
@Autowired Service service;),测试中应替换为 mock 的接口实现,通常用@Mock+@InjectMocks或手动 set - 切忌 mock 抽象父类后期望子类方法被拦截——Mockito 不支持基于继承链的自动委托;子类方法未显式 stub 就会调用真实逻辑(除非用
spy或thenCallRealMethod())
正确写法:mock 接口,而非实现类(推荐)
接口天然适合 mock,且与多态设计一致。只要被测代码面向接口编程,mock 接口就能覆盖所有实现。
// 定义
public interface PaymentService {
String process(double amount);
}
public class AlipayService implements PaymentService { ... }
public class WechatService implements PaymentService { ... }
// 被测类(依赖接口)
public class OrderProcessor {
private final PaymentService paymentService;
public OrderProcessor(PaymentService paymentService) {
this.paymentService = paymentService;
}
public String execute(double amount) {
return paymentService.process(amount); // 多态调用点
}
}
测试时直接 mock 接口:
立即学习“Java免费学习笔记(深入)”;
@ExtendWith(MockitoExtension.class)
class OrderProcessorTest {
@Mock PaymentService paymentService; // mock 接口
@InjectMocks OrderProcessor processor;
@Test
void should_return_mock_result_when_process_called() {
// ✅ 正确:对 mock 接口实例 stub
Mockito.when(paymentService.process(100.0)).thenReturn("ALIPAY_123");
String result = processor.execute(100.0);
assertThat(result).isEqualTo("ALIPAY_123");
}
}
需要 mock 具体实现类的场景及注意事项
少数情况需验证某实现类行为(如测试模板方法、或 legacy 代码强耦合实现类),此时必须 mock 实际类型,并确保被测代码使用的是该 mock 实例。
- 用
Mockito.mock(ConcreteClass.class)创建 mock,但注意:它默认只 mock 该类声明的方法,不自动处理父类/接口方法(除非用withSettings().lenient()或显式 stub) - 若该实现类实现了接口,且你用接口引用接收它(如
PaymentService s = mock(AlipayService.class);),then stub 必须在 mock 实例上操作,不能对接口类型变量调用 when() - 避免 mock 非 final 类的构造器或静态方法——它们不属于多态调用范畴,应改用
Mockito.spy()或Mockito.mockStatic()
常见陷阱与绕过方式
以下写法无效或易出错:
-
when(((PaymentService) mockAlipay).process(...))—— 强转不改变 mock 实例本质,但容易误导;直接 mock 接口更清晰 - 在测试中 new 出真实实现类再 mock 它——Mockito 无法修改已创建对象的行为;必须用
mock()或spy()创建可控实例 - stub 了父接口方法,却期望子类重写方法返回不同值——必须 stub 子类 mock 实例上的该方法,或改用
spy(new Concrete())并用doReturn(...).when(spy).method()


















