抽象类单元测试需用spy或mock:spy基于真实子类保留默认逻辑并选择性模拟方法,适用于有默认实现的场景;mock则完全虚拟化抽象类,仅验证契约响应。

抽象类在单元测试中不能直接实例化,但 Mock 框架(如 Mockito)提供了两种主流方式应对:一是用 Spy 保留部分真实逻辑并选择性模拟方法;二是用 Mock 完全替代抽象类行为(适用于仅需接口契约、不依赖具体实现的场景)。关键不在于“模拟抽象类本身”,而在于如何让测试代码能控制其可变行为,同时不破坏原有设计意图。
用 Spy 模拟抽象类的可重写方法
当抽象类已提供默认实现(如模板方法、公共校验、日志记录等),且你只想干预其中几个抽象或可覆盖的方法时,Spy 是更自然的选择。它基于真实子类实例创建,既保留基础逻辑,又允许精准替换指定行为。
- 推荐写法:用
@Spy注解或Mockito.spy(new ConcreteSubclass())创建对象 - 替换方法必须用
doReturn(...).when(spy).method()或doThrow(...).when(spy).method()—— 不能用when().thenReturn(),否则会触发真实方法执行 - 适合场景:支付策略抽象类中保留本地幂等检查,只 Mock 远程调用;或审批流程中固定前置校验,只替换审批决策逻辑
用 Mock 直接模拟抽象类(需谨慎)
Mockito 支持对抽象类调用 mock(YourAbstractClass.class),生成一个完全虚拟的实例。这种方式跳过所有真实逻辑,适用于你只关心“契约响应”而非“实现路径”的测试目标。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 适用前提:抽象类定义了明确的 public/protected 方法签名,且测试不依赖其内部状态或构造逻辑
- 注意:final 方法、static 方法、private 方法无法被 Mock;构造器逻辑也不会执行
- 典型用例:验证某服务在不同策略下是否调用了抽象类的
execute()方法,而不关心该方法内部怎么跑
确保抽象类设计利于测试
Mock 能否有效介入,根本上取决于抽象类是否遵循面向抽象编程原则。如果子类行为高度耦合于具体实现细节,Mock 就容易失效或难以维护。
- 抽象方法应聚焦职责边界,避免包含 I/O、时间、随机等不可控因素
- 模板方法中可变部分尽量声明为 protected 抽象方法,便于 Spy 替换
- 避免在抽象类构造器中做重量级初始化(如连接池、文件读取),否则 Spy 初始化失败
- 若抽象类依赖外部对象,建议通过构造函数注入,方便测试时传入 Mock 实例
验证调用是否走多态路径
抽象类的价值常体现在运行时动态分派。光有返回值不够,还要确认被测代码确实通过多态委托到了抽象类方法——这才是设计落地的关键证据。
- 用
verify(spy).doSomething()确认方法被调用,而非空实现或条件跳过 - 结合
times(1)、never()或atLeastOnce()核查分支逻辑中的调用频次 - 若方法被多次调用且参数不同,可用
argThat(...)匹配特定输入,验证路由逻辑正确
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










