Spring Boot Mocking Service测试空指针异常的解决方法
嘿,我看你在运行UserServiceImpl的测试时碰到了空指针异常,结合你的代码和异常栈,我来帮你梳理下问题根源和修复方案:
首先看异常信息:java.lang.NullPointerException at com.example.demo.service.database.impl.UserServiceImplTest.getById(UserServiceImplTest.java:69),这个空指针大概率是因为UserServiceImpl里的userRepository没有被Mockito正确注入,导致调用userRepository.findOne(id)时触发空指针。
具体修复步骤
1. 别混用Spring Runner和Mockito注解(核心问题)
你现在用的是@RunWith(SpringJUnit4ClassRunner.class),这是用来跑Spring集成测试的,会加载整个Spring上下文,但你的测试是单元测试,不需要加载Spring容器,反而会干扰Mockito的mock对象注入。换成Mockito专门的Runner就行:
// 替换掉原来的SpringJUnit4ClassRunner @RunWith(MockitoJUnitRunner.class) public class UserServiceImplTest { @InjectMocks UserServiceImpl userService; @Mock UserRepository userRepositoryMock; // 原来的setUp方法可以删掉了,Mockito Runner会自动初始化所有注解的对象 @Test public void getById() { long id = 12; when(userRepositoryMock.findOne(id)).thenReturn(new User(id)); Assert.assertEquals(id, userService.getById(id).getId()); } }
2. 如果你坚持用Spring Runner(不推荐单元测试用)
要是因为某些原因必须用Spring的Runner,那得确保Mockito的初始化逻辑正确,并且要加上@MockBean来替代@Mock,让Spring容器管理mock对象:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {UserServiceImpl.class}) // 只加载必要的类 public class UserServiceImplTest { @Autowired UserServiceImpl userService; @MockBean UserRepository userRepositoryMock; @Test public void getById() { long id = 12; when(userRepositoryMock.findOne(id)).thenReturn(new User(id)); Assert.assertEquals(id, userService.getById(id).getId()); } }
不过这种方式更适合集成测试,单元测试还是用Mockito Runner更轻便。
3. 检查Mockito初始化方法(如果不用Runner)
要是你不想用Runner,手动初始化的话,注意Mockito 2.x之后initMocks已经过时,换成openMocks:
@Before public void setUp(){ MockitoAnnotations.openMocks(this); // 替换原来的initMocks }
4. 验证对象是否初始化成功
可以在测试方法里加个简单的断言,确认mock和service都不为null,方便排查:
@Test public void getById() { assertNotNull(userRepositoryMock); assertNotNull(userService); // 剩下的测试逻辑 }
为什么会出现这个问题?
你原来的代码里,用Spring Runner加载上下文,但没有把mock对象注册到Spring容器里,同时Mockito的@InjectMocks因为Spring Runner的存在没有正常工作,导致UserServiceImpl里的userRepository还是null,调用它的方法就抛出了空指针。
内容的提问来源于stack exchange,提问作者fuad022

