接口适合直接Mock,抽象类应优先继承测试;接口无状态易模拟,抽象类含构造逻辑和protected成员,mock易失真,需用测试子类覆盖抽象方法验证行为。

接口与抽象类在单元测试中模拟抽象行为,核心区别在于:接口天然适合 mock,抽象类更适合继承测试。选对方式,测试才干净、稳定、可维护。
接口:直接 Mock,零成本替换实现
接口没有状态、无构造逻辑、无 protected 成员,Mock 框架(如 Mockito、Spock)能安全生成代理对象。
- 调用方只依赖接口类型,测试时用 Mockito.mock(YourInterface.class) 即可注入可控行为
- default 方法不影响 mock —— 可选择 stub,也可让其自然执行(只要不依赖外部资源)
- 例如 PaymentClient 接口,测试 OrderService 时只需 mock pay() 和 refund(),完全隔离 HTTP、签名等细节
抽象类:少 mock,多继承 + 轻量测试子类
抽象类带字段、构造器、模板方法和 protected 成员,强行 mock 容易跳过初始化、绕过校验、导致行为失真。
- 推荐做法:写一个匿名或私有测试子类,仅覆盖抽象方法,其余逻辑复用父类
- 例如测试 Shape 抽象类的 displayColor() 行为,可写 new Circle(5) { @Override public double area() { return 78.54; } },再调用父类方法断言
- 若必须 mock 抽象方法(如 Spock 场景),需借助 PowerMock 等工具,但属于例外,不是首选
混合场景:SDK 或服务层测试怎么切分边界
当一个类既 extends 抽象类又 implements 多个接口时,测试策略要按职责分离:
- 验证高层业务逻辑(如 OrderService.process())→ mock 所依赖的 接口(如 PaymentClient、InventoryClient)
- 验证抽象骨架行为(如 AbstractHttpClient.execute() 的签名+日志流程)→ 写测试子类,传入 mock 的 buildHttpRequest() 返回值,再断言最终 Response 结构
- 验证某接口能力是否被正确支持(如 Retryable)→ 在测试子类中启用该接口,并检查重试是否触发,而非 mock 接口本身
关键判断原则:看你在测什么
不是语法决定测试方式,而是设计意图。
- 你测的是“契约是否被满足”?→ 用接口 + mock
- 你测的是“骨架是否工作正常”?→ 用继承 + 断言
- 你测的是“某个具体实现是否符合抽象规范”?→ 让该实现类参与测试,不 mock 它的父类或接口
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











