
多态特性在单元测试中不是“模拟”出来的,而是通过设计让测试自然受益于多态带来的可替换性与行为隔离。关键不在于强行模拟多态本身,而在于利用多态结构合理组织被测类与依赖,使测试能聚焦行为、避开实现细节。
用接口或抽象类定义契约,测试时注入真实子类或轻量模拟实现
多态的核心是“父类型引用指向子类型对象”。单元测试中,应避免直接 new 具体实现类(尤其是含外部依赖的),而是:
- 将被测类依赖声明为接口或抽象类(如
PaymentService接口) - 测试时传入一个简单、可控的实现(如
MockPaymentService或InMemoryPaymentService) - 不用 Mockito 等框架也能完成,纯 Java 写个内部类即可
例如:
public class OrderService {
private final PaymentService paymentService; // 接口类型,非具体实现
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public boolean process(Order order) {
return paymentService.charge(order.getAmount());
}
}测试时可直接 new 一个满足接口的轻量实现:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
@Test
void process_shouldReturnTrueWhenChargeSucceeds() {
PaymentService mockService = new PaymentService() {
@Override
public boolean charge(double amount) {
return true; // 固定返回,无需网络或数据库
}
};
OrderService service = new OrderService(mockService);
assertTrue(service.process(new Order(100.0)));
}避免在测试中验证“是否调用了某个子类方法”,而应验证“行为结果是否符合预期”
多态的意义是解耦调用方与具体实现。测试重点不是“它用了 Dog 还是 Cat”,而是“叫唤后是否返回了预期声音”。
- ✅ 正确:检查
animal.speak()返回"汪汪"或"喵喵",取决于你传入的是哪个实例 - ❌ 错误:用
verify(mockDog).bark()强制断言某子类被调用——这把测试和实现细节绑死了
继承链过深时,优先测试子类自身行为,而非层层回溯父类逻辑
如果 PremiumUser extends User extends Person,测试 PremiumUser 时:
- 只需覆盖其新增逻辑(如
getDiscountRate())和重写逻辑(如calculateFee()) - 不必重复验证
Person.getName()是否正常——那是PersonTest的职责 - 父类行为稳定,子类测试只需保证“在父类基础上做了正确扩展”
谨慎使用 Mockito 的 when().thenReturn() 模拟多态分支,除非必要
当被测逻辑根据运行时类型做不同处理(如 if (obj instanceof VIP) {...}),可考虑:
- 重构为策略模式或访问者模式,让类型判断逻辑外移、可测
- 若暂时无法重构,可用
Mockito.mock(User.class)+thenAnswer()控制返回,但要明确这是临时方案,不是设计常态
多态本身不增加测试难度,反而是降低难度的杠杆——只要依赖抽象、行为清晰、职责分明,单元测试就能干净利落地验证每种表现形式。
立即学习“Java免费学习笔记(深入)”;

















