多态是Mock介入的结构基础,前提是代码依赖抽象而非具体实现;正确方式为注入接口,错误方式为方法内new实现类;Mockito支持模拟不同子类行为、异常及参数匹配,Spy适用于抽象类部分模拟,verify用于验证多态调用是否符合预期。

多态本身不是被“模拟”的对象,而是让 Mock 能够自然介入的结构基础。关键在于代码是否按多态的设计原则编写——依赖父类或接口,而不是具体子类。只要满足这个前提,Mock 就能无缝替换任意子类行为,无需改业务逻辑。
确保被测代码面向抽象编程
这是整个机制成立的前提。如果方法里直接 new 一个实现类(比如 new UserServiceImpl()),那多态就断了,Mock 框架完全无法接管。
- ✅ 正确方式:构造函数或 setter 注入接口类型,如 UserGateway、PaymentStrategy
- ❌ 错误方式:在业务方法内部写 new AlipayPayment() 或 new WechatPayment()
- 接口定义要覆盖所有需要测试的交互点,比如 pay()、refund()、queryStatus()
用 Mockito 创建并配置不同子类行为
Mockito 可以为同一接口生成多个 Mock 实例,每个代表一种子类行为,比如 VIP 用户、冻结账户、网络超时等场景。
- 用 @Mock 声明字段,配合 @ExtendWith(MockitoExtension.class) 自动初始化
- 用 when(...).thenReturn(...) 模拟正常返回,例如 when(gateway.findById(1L)).thenReturn(Optional.of(new User(true)))
- 用 when(...).thenThrow(...) 模拟子类可能抛出的特定异常,如 InsufficientBalanceException
- 支持参数匹配器(anyString()、eq("prod")、argThat(...)),让同一个 Mock 对不同输入返回不同结果
处理抽象类场景:用 Spy 保留部分真实逻辑
当多态基于抽象类(而非纯接口),且该类已有默认实现(比如模板方法中固定日志逻辑、公共校验),又只想 Mock 其中几个抽象/可重写方法时,Spy 是更合适的选择。
立即学习“Java免费学习笔记(深入)”;
- 用 Mockito.spy(new ConcreteSubclass()) 或 @Spy 注解创建部分模拟对象
- 用 doReturn(...).when(spy).method() 替换指定方法行为,其余方法仍走原始逻辑
- 适合测试含默认流程但需干预某步决策的场景,比如支付策略中只 Mock 支付网关调用,保留本地幂等校验
验证多态调用是否按预期委托
Mock 的价值不仅在于提供返回值,更在于确认运行时是否真的通过多态路径调用了依赖对象——这才是对设计意图的检验。
- 用 verify(mock).method(args) 确认方法被调用,避免空实现或条件跳过
- 用 verify(mock, times(1)) 或 verify(mock, never()) 核查调用频次,尤其在分支逻辑中
- 结合 ArgumentCaptor 捕获实际传入参数,验证是否传递了正确的上下文(如 userId、orderNo)
- 若业务逻辑本应触发子类 A,却意外调用了子类 B 的实现,verify 会立刻暴露问题


















