You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()还不够:

  • 比如你MockuserService.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:18:11