java单元测试中多态通过接口/抽象类引用支持mock替换,前提是依赖抽象而非具体实现;若代码中直接new子类则无法mock;mockito可创建动态代理并定义行为,spy适用于部分mock抽象类,verify可验证多态调用是否正确委托。

在 Java 单元测试中,多态本身不直接“被利用”,而是通过多态的特性(如父类/接口引用指向子类实例)为 Mock 切入提供天然支持——只要代码面向抽象编程(依赖接口或父类),就能用 Mock 对象无缝替换真实子类,无需修改被测逻辑。
确保被测代码依赖抽象而非具体实现
这是前提。如果方法内部直接 new 一个子类(如 new UserServiceImpl()),就破坏了多态可替换性,Mock 框架无法介入。
✅ 正确写法(面向接口):
public class OrderService {
private final UserGateway userGateway; // 接口类型,非具体实现
public OrderService(UserGateway userGateway) {
this.userGateway = userGateway;
}
public boolean isVip(Long userId) {
return userGateway.findById(userId).map(User::isVip).orElse(false);
}
}
这样在测试时,就能把 UserGateway 的任意实现(真实类、Mock、Stub)注入进去。
用 Mockito 创建和配置 Mock 对象
Mockito 是最常用的选择。它能生成接口或抽象类的动态代理对象,并允许你控制其行为。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 用
@Mock声明 Mock 字段,配合@ExtendWith(MockitoExtension.class)(JUnit 5)自动初始化 - 用
when(...).thenReturn(...)定义方法返回值,模拟不同子类行为(比如模拟 VIP 用户 vs 普通用户) - 用
when(...).thenThrow(...)模拟异常路径,覆盖子类可能抛出的业务异常
示例:
@Test
void isVip_returnsTrue_forVipUser() {
User vipUser = new User(1L, true);
when(userGateway.findById(1L)).thenReturn(Optional.of(vipUser));
boolean result = orderService.isVip(1L);
assertTrue(result);
}
用 Spy 或部分 Mock 处理含默认逻辑的抽象类
如果多态基于抽象类(而非接口),且该抽象类有部分已实现的方法,而你想只 Mock 其中几个方法,保留其余逻辑,可用 @Spy 或 Mockito.spy()。
- Spy 是对真实对象的包装,调用未 stub 的方法会执行原逻辑
- 适合测试抽象类子类共有的模板方法,只替换其中可变步骤(比如
templateMethod() { before(); doWork(); after(); },只 MockdoWork())
注意:避免对 final 类、private 方法或静态方法使用 Spy/Mock,需借助 Mockito-inline 或其他工具(如 PowerMock 已不推荐)。
验证多态行为是否按预期委托
除了断言结果,还可验证方法调用本身,确认多态分派正确发生:
- 用
verify(mock).someMethod(...)确保被测代码确实调用了依赖的抽象方法 - 结合
times(1)、never()或atLeastOnce()验证调用频次,防止因条件分支导致意外跳过 - 若多个 Mock 参与协作(如
UserGateway和NotificationService),可分别验证各自交互,体现多态下各组件职责分离
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










