使用@InjectMocks注入前初始化Mock对象内部(Foo2)的问题求助
解决Mockito中@InjectMocks注入前初始化Foo2内部结构的问题
我完全懂你的痛点:你不想把Foo2完全Mock掉,而是希望它内部的某个对象用真实实例(基于ObjectA初始化),这样调用Foo2的方法时,这个内部对象能返回你要的结果,但用@InjectMocks的时候总是搞不定初始化时机对吧?
下面给你两个靠谱的解决方案,根据你的场景选就行:
方案1:用@Spy替代@Mock + 手动初始化内部对象
如果Foo2的内部对象可以通过Setter或者包私有方式访问,这个方案最方便:
- 别再给Foo2加@Mock了,换成@Spy。@Spy的好处是默认会走Foo2的真实方法逻辑,只有你明确Stub的方法才会被Mock,完美契合你要保留部分真实逻辑的需求
- 在测试类的初始化方法(JUnit4用@Before,JUnit5用@BeforeEach)里,手动用ObjectA创建真实的内部对象,然后赋值给Foo2
举个代码例子:
public class YourTest { @Spy private Foo2 foo2; // 用Spy保留真实方法 @InjectMocks private YourServiceUnderTest service; // 依赖Foo2的待测试类 @BeforeEach void setUp() { // 先创建你需要的ObjectA真实实例 ObjectA realObjectA = new ObjectA("你要的参数值"); // 假设Foo2内部的对象是bar,用ObjectA初始化它 Bar realBar = new Bar(realObjectA); // 如果有Setter直接调用,没有的话用反射 foo2.setBar(realBar); // 要是你需要Stub Foo2的某些方法,照样可以写 // when(foo2.someMethod()).thenReturn("自定义返回"); } @Test void testYourBusinessLogic() { service.execute(); // 此时Foo2的bar是真实初始化的,会按ObjectA的参数返回预期结果 // 这里写你的断言逻辑... } }
方案2:手动构造Foo2实例后交给@InjectMocks
如果Foo2的内部对象必须在构造时传入(比如没有Setter),那直接手动创建Foo2的真实实例就行:
- 测试类里的Foo2字段不要加任何Mockito注解
- 在初始化方法里,先创建ObjectA,再用它构造Foo2的内部对象,最后实例化Foo2
- @InjectMocks会自动把这个手动创建的Foo2注入到你的待测试类里
代码示例:
public class YourTest { private Foo2 foo2; // 不标注Mock/Spy,手动初始化 @InjectMocks private YourServiceUnderTest service; @BeforeEach void setUp() { // 一步一步构造真实依赖链 ObjectA realObjectA = new ObjectA("预期参数"); Bar realBar = new Bar(realObjectA); foo2 = new Foo2(realBar); // 完全真实的Foo2实例 } @Test void testYourBusinessLogic() { service.execute(); // Foo2内部的bar已经基于ObjectA初始化,能返回你要的结果 } }
踩坑提醒
- 之前用@Mock标注Foo2的话,Mockito会生成一个“空壳”Mock对象,它的所有内部字段都是null,调用方法时不会走真实逻辑,这就是你之前代码跑不通的核心原因
- 如果Foo2的内部对象是私有字段且没有Setter,可以用Mockito自带的
Whitebox.setInternalState()来强制设置,比如:
Whitebox.setInternalState(foo2, "bar", realBar);
内容的提问来源于stack exchange,提问作者Saad
相关产品推荐
相关产品推荐

