如何测试存在链式@Autowired依赖的方法?Mockito测试时遇空指针如何解决
空指针异常原因及修复方案
触发空指针的核心原因有两个:
- 测试类未启用Mockito注解处理器,
@InjectMocks和@Spy注解未生效,导致Class1中的autoWiredObject字段本身为null - 你手动实例化的
AutoWiredObject内部的@Autowired依赖没有被注入,调用setAllValues时内部访问其他注入对象就会触发空指针
如果你仅需要测试Class1的getAccount逻辑,不需要验证AutoWiredObject的内部执行细节,直接Mock外部依赖是最简单的方案,修改后测试代码如下(JUnit5版本):
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.times; @ExtendWith(MockitoExtension.class) // 必须加,用来激活Mockito注解 public class Class1Test { @InjectMocks private Class1 myClass; @Mock // 直接Mock外部依赖,不需要使用真实实例 private AutoWiredObject autoWiredObject; @Test public void testGetAccount() { // 模拟setAllValues的行为,给入参的object的value属性赋值 doAnswer(invocation -> { Object1 obj = invocation.getArgument(0); obj.set("value", "模拟赋值"); // 可根据Object1的实际设值方法调整 return null; }).when(autoWiredObject).setAllValues(any(Object1.class)); Object1 object = myClass.getAccount(true); assertNotNull(object.get("value")); } }
如果使用JUnit4,将@ExtendWith(MockitoExtension.class)替换为@RunWith(MockitoJUnitRunner.class)即可。
多层Autowired依赖链的最优单元测试方案
- 纯单元测试优先走隔离方案:被测类的所有外部依赖全部用
@Mock替换,不需要引入依赖的真实实现,也不需要处理依赖的依赖问题,只需要Mock依赖对外暴露的方法的行为即可,测试执行速度快,且不会受依赖内部逻辑变动的影响 - 如果需要连带测试依赖的内部逻辑,属于集成测试范畴,可以配合Spring Test的
@SpringBootTest注解启动Spring上下文自动注入全链路依赖,但启动上下文耗时久,不适用于快速执行的单元测试 - 如果一定要使用
@Spy调用依赖的真实方法,需要手动给Spy实例的内部Autowired字段赋值,或配合Spring Test注入Spy实例,复杂度远高于直接Mock依赖
测试
autowiredObject.setAllValues(object)逻辑的简便方式 - 如果你只需要验证
Class1确实调用了该方法,不需要验证赋值逻辑,直接使用Mockito的verify方法即可,不需要模拟方法行为:
@Test public void testSetAllValuesInvoke() { Object1 object = myClass.getAccount(true); // 验证setAllValues被调用了1次,且入参就是返回的object实例 verify(autoWiredObject, times(1)).setAllValues(object); }
- 如果你要验证
setAllValues本身的逻辑,单独编写AutoWiredObject的单元测试即可,不需要和Class1的测试耦合,每个类的单元测试仅负责验证自身逻辑。
内容的提问来源于stack exchange,提问作者mchl45
相关产品推荐
相关产品推荐

