@InjectMocks 不创建 Mock,只将已声明的 @Mock/@Spy 实例按类型或名称注入被测对象字段、构造器或 setter;需配合 @ExtendWith(MockitoExtension.class) 或 openMocks() 才生效,且必须先声明 @Mock 再声明 @InjectMocks。

@InjectMocks 的作用不是“自动装配”,而是“自动注入已创建的 Mock 实例”——它本身不创建依赖,只负责把用 @Mock(或 @Spy)声明好的模拟对象,按类型或字段名匹配后,设进被测对象的对应字段里。关键在于:它依赖你提前准备好 Mock,再由它完成“塞进去”这一步。
被测对象必须有可注入的入口
InjectMocks 只对以下方式声明的依赖生效:
- public、protected 或 package-private 的成员变量(最常用)
- 有参构造函数(需配合 @Mock 注解的参数类型能一一匹配)
- Setter 方法(方法名需为 setXxx,且参数类型与 @Mock 字段一致)
它不会调用无参构造器后再反射设值,也不会处理 final 字段或私有字段(除非开启 Mockito 的 inline mock 功能并配合 byte-buddy)。例如:
public class OrderService {
private final PaymentGateway gateway; // final 字段 → @InjectMocks 无法注入
private EmailSender emailSender; // 可注入
public OrderService(PaymentGateway gateway, EmailSender emailSender) {
this.gateway = gateway;
this.emailSender = emailSender;
}
}
若 gateway 是 final,就必须用构造函数注入方式,并确保 @Mock PaymentGateway 和 @Mock EmailSender 都存在,Mockito 才能通过构造器完成实例化和注入。
立即学习“Java免费学习笔记(深入)”;
@Mock 和 @InjectMocks 必须成对出现
单独写 @InjectMocks 没有意义——它找不到可注入的 Mock 对象。正确写法是:
- 先用 @Mock 声明所有依赖项(如 @Mock UserRepository repo)
- 再用 @InjectMocks 声明被测对象(如 @InjectMocks OrderService service)
- 在测试类初始化阶段触发注入(JUnit 5 中通常靠 @ExtendWith(MockitoExtension.class) 自动完成)
没有 @ExtendWith(MockitoExtension.class) 或手动调用 MockitoAnnotations.openMocks(this),@Mock 和 @InjectMocks 都不会生效。这是初学者最常见的遗漏点。
注入过程不等于行为定义,还需手动 stub
@InjectMocks 只管“把 Mock 对象放进去”,不管“Mock 对象怎么 behave”。比如:
- service 调用 repo.findById(1L),你得自己写 when(repo.findById(1L)).thenReturn(user)
- 否则默认返回 null(引用类型)或 0/ false(基本类型包装类),很可能导致 NPE 或逻辑错误
- 如果依赖是接口,Mockito 默认生成的是宽松 mock(lenient),不会因未 stub 的调用而失败;但建议显式 stub 关键路径
注意字段命名与类型冲突
当多个 @Mock 字段类型相同时(比如两个 List<String>),InjectMocks 会按字段名匹配:
- 若被测对象字段叫 orderItems,它会优先找名为 orderItems 的 @Mock 字段
- 若没找到同名字段,则按类型匹配——但类型相同就可能注入错对象
- 解决办法:用 @Mock(name = "orderItems") 显式指定名称,或改用构造器注入避免歧义
另外,@Spy 和 @Mock 混用时,@InjectMocks 会优先注入 @Mock 对象;若某依赖既声明了 @Mock 又声明了 @Spy,以 @Mock 为准。


















