Mockito:被Mock的服务参数抛出空指针异常排查
排查Mock后仍出现NullPointerException的常见原因
这种Mock完还碰上空指针的情况我之前踩过好几个坑,大概率是Mock的配置或者匹配逻辑没跟上,咱们一步步来排查:
1. Mock对象没被正确注入到控制器
最常见的问题就是你Mock的依赖根本没进到控制器实例里:
- 如果是单元测试:得确保用了
@ExtendWith(MockitoExtension.class),然后给依赖加@Mock,给控制器加@InjectMocks——后者会自动把Mock的依赖注入到控制器的成员变量里。要是你手动new了控制器,那@InjectMocks就白加了,控制器用的还是真实的依赖(或者没初始化的依赖)。 - 如果是Spring Boot集成测试:别用普通的
@Mock,得用@MockBean,它会自动替换Spring容器里对应的真实Bean,这样控制器才能拿到Mock的实例。
2. Mock的方法调用匹配不精准
你以为Mock了方法,但实际代码调用的参数和你Mock的不匹配,导致Mock没生效,默认返回null:
- 比如你写了
when(userService.getById(1L)).thenReturn(mockUser),但控制器里传的是null或者另一个ID,这时候Mockito会找不到匹配的Mock,返回默认的null。 - 解决方法:用匹配器放宽条件,比如
anyLong()、any(User.class),或者用eq()来精确匹配。另外可以加一句verify(userService).getById(anyLong())来确认你的Mock方法到底有没有被调用——如果没触发,那肯定是参数匹配错了。
3. 嵌套对象的Mock没做全
如果空指针是出现在嵌套调用里(比如user.getAddress().getCity()),只Mock了外层的userService.getById()还不够:
- 比如你Mock
userService.getById()返回了一个真实的User对象,但这个User的address属性是null,那调用getAddress()就会空指针。 - 解决方法:要么给返回的对象手动赋值,要么链式Mock:
User mockUser = Mockito.mock(User.class); Address mockAddress = Mockito.mock(Address.class); when(mockUser.getAddress()).thenReturn(mockAddress); when(mockAddress.getCity()).thenReturn("Beijing"); when(userService.getById(anyLong())).thenReturn(mockUser);
4. 注解配置的细节问题
有时候控制器里的依赖注入用了@Qualifier指定Bean名称,但Mock的时候没对应上:
- 比如控制器里写的是
@Autowired @Qualifier("userServiceImpl") private UserService userService;,那测试里的@MockBean就得加上name = "userServiceImpl",不然Spring会找不到对应的MockBean,还是注入真实的实例。
举个正确的单元测试示例
@ExtendWith(MockitoExtension.class) public class UserControllerTest { @Mock private UserService userService; // Mock依赖服务 @InjectMocks private UserController userController; // 自动注入Mock到控制器 @Test public void testGetUserDetail() { // 构建嵌套的Mock对象 Address mockAddr = new Address(); mockAddr.setCity("Shanghai"); User mockUser = new User(); mockUser.setId(1L); mockUser.setAddress(mockAddr); // Mock方法调用 when(userService.getById(anyLong())).thenReturn(mockUser); // 调用控制器方法 ResponseEntity<User> result = userController.getUser(1L); // 验证结果和Mock调用 assertNotNull(result.getBody()); assertNotNull(result.getBody().getAddress()); assertEquals("Shanghai", result.getBody().getAddress().getCity()); verify(userService).getById(1L); } }
如果排查完这些还是有问题,可以把控制器里抛空指针的具体代码、你的测试代码片段贴出来,能更快定位问题~
内容的提问来源于stack exchange,提问作者OEH
相关产品推荐
相关产品推荐

