java多态下mock的关键是依赖注入抽象类型:被测类通过构造函数等持有接口/父类引用,再用mockito.mock()创建模拟对象并注入;若直接new具体实现则无法mock。

Java 多态下做单元测试时,Mock 对象替换的关键在于:**不直接 new 实例,而是通过依赖注入(如构造函数、Setter 或接口变量)让被测类持有抽象类型(接口或父类),再用 Mock 框架(如 Mockito)生成该抽象类型的模拟实现来替换真实依赖。**
确保被测类依赖抽象而非具体实现
多态是 Mock 的前提。如果代码里写的是 new UserServiceImpl(),就无法在测试中替换;必须改为依赖 UserService 接口:
- ✅ 正确方式:成员变量声明为接口类型,并通过构造函数传入
- ❌ 错误方式:在方法内部直接 new 具体实现类
例如:
public class UserController {
private final UserService userService; // 接口类型
public UserController(UserService userService) { // 构造注入
this.userService = userService;
}
public String getName(Long id) {
return userService.findById(id).getName();
}
}
用 Mockito 创建并注入 Mock 对象
在 JUnit 测试中,使用 Mockito.mock() 创建接口的模拟对象,再通过构造函数或 Setter 注入到被测对象中:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 调用
Mockito.mock(UserService.class)得到一个可控制行为的代理对象 - 用
when(mock.findById(1L)).thenReturn(new User("Alice"))定义返回逻辑 - 将 mock 对象传给
UserController构造器,完成依赖替换
示例测试片段:
@Test
void shouldReturnNameWhenUserExists() {
UserService mockService = Mockito.mock(UserService.class);
User user = new User("Alice");
when(mockService.findById(1L)).thenReturn(user);
UserController controller = new UserController(mockService); // 注入 mock
String result = controller.getName(1L);
assertEquals("Alice", result);
}
配合 @Mock 和 @InjectMocks 简化写法(可选)
使用 MockitoJUnitRunner 或 @ExtendWith(MockitoExtension.class) 后,可借助注解自动创建和注入:
-
@Mock UserService userService;:自动生成 mock 实例 -
@InjectMocks UserController controller;:自动把标注为 @Mock 的字段注入到 controller 中(按类型匹配)
注意:@InjectMocks 只对构造注入或 Setter 注入有效,不支持字段直接赋值(private final 需构造注入才可被识别)。
避免常见陷阱
多态 Mock 容易出错的地方:
- 被测类中若存在
new XXXServiceImpl(),Mock 无效——必须重构为依赖注入 - Mock 的方法未 stub(即没写
when(...).thenReturn(...)),默认返回 null 或空集合,可能引发 NPE - 对接口默认方法(default method)Mock 时,需用
mock(MyInterface.class, CALLS_REAL_METHODS)才能触发默认逻辑(一般不推荐,默认方法应尽量无副作用) - 静态方法、final 类/方法无法被 Mockito(默认配置)Mock,需改用 PowerMockito 或迁移到非 final 设计
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










