接口定义行为契约实现测试友好型多态:解耦实现与调用,用接口声明引用、构造函数注入依赖、重写方法无副作用、避免静态/final方法参与多态。

用接口定义行为契约
测试友好型多态代码,第一步是把具体实现和调用逻辑解耦。优先使用接口而非抽象类或具体父类来声明引用类型。比如定义 PaymentProcessor 接口,而不是 AbstractPayment 类。这样测试时可以轻松注入模拟实现(如 MockPaymentProcessor),无需启动真实支付网关。
- 接口方法签名清晰、无状态、不依赖外部资源
- 避免在接口中定义静态方法或默认方法(除非逻辑纯且确定不需 mock)
- 每个接口职责单一,例如 Notifier 只负责通知,Validator 只负责校验
构造函数注入依赖,避免 new 实例
在业务类中,不要直接 new Dog() 或 new Cat(),而是通过构造函数接收父类型或接口类型的参数。这样单元测试时可传入任意子类或模拟对象,完全控制被测对象的行为边界。
- 错误写法:
Animal pet = new Dog();—— 测试时无法替换 - 正确写法:
public class PetOwner { private final Animal pet; public PetOwner(Animal pet) { this.pet = pet; } } - 配合测试框架(如 JUnit + Mockito),一行
new PetOwner(mock(Cat.class))就能隔离验证逻辑
让重写方法无副作用、可预测
多态方法(如 eat()、process())在测试中要能稳定返回结果或抛出明确异常。避免在重写方法里写日志、发 HTTP 请求、操作数据库等副作用。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 把副作用提取到单独的服务类中,并通过依赖注入传入
- 重写方法只做核心计算或状态转换,例如:
return "猫吃鱼";而不是System.out.println("猫吃鱼"); sendToKafka(...); - 这样测试只需断言返回值或异常类型,不需要捕获输出流或启动中间件
避免静态方法和 final 方法参与多态逻辑
静态方法和被 final 修饰的方法不会被动态绑定,它们的调用在编译期就锁死,无法在测试中 mock 或替换。如果某段逻辑需要测试时行为可变,就一定不能放在静态或 final 方法里。
立即学习“Java免费学习笔记(深入)”;
- 例如
Animal.sleep()若是 static,则new Cat()调用的仍是 Animal 的版本,与多态无关 - 字段访问也不具备多态性(
am.num取的是 Animal 的 num,不是 Cat 的),测试时别误以为它会随对象类型变化 - 真正参与多态的,仅限于非 private、非 static、非 final 的实例方法

















