Junit5编写RestController集成测试出现NullPointerException如何解决
可能的问题原因及对应解决方案
Postman调用正常是因为请求时携带了正确的分页参数,且运行环境中MyService、ModelMapper都是真实初始化的实例,不存在Mock打桩失效、返回默认null的情况,测试场景下的空指针大概率是以下几个原因导致:
测试请求未传递分页参数,Mock匹配失效
你的测试代码发起的请求是mockMvc.perform(MockMvcRequestBuilders.get("/test")),没有携带pageNumber、pageSize参数:- 如果控制器方法的分页参数没有配置默认值,入参直接为null,若方法内用基础类型接收会触发拆箱空指针
- 你给MyService的打桩逻辑是
Mockito.when(myService.retrieveAll(1,20)).thenReturn(...),如果实际请求传递的参数和1、20不匹配(比如Spring分页默认page从0开始、默认size是10),则该打桩不会生效,myService.retrieveAll会返回默认值null,后续操作null对象直接触发空指针
解决方法:请求时携带对应参数,或者调整Mock匹配规则为任意参数:
// 方式1:请求携带参数 mockMvc.perform(MockMvcRequestBuilders.get("/test") .param("pageNumber", "1") .param("pageSize", "20")) // 方式2:Mock匹配任意参数 Mockito.when(myService.retrieveAll(anyInt(),anyInt())).thenReturn(objFactory.createRandomList());Service返回类型不匹配
你的控制器方法返回类型是ResponseEntity<Page<Dto>>,说明业务逻辑中MyService的retrieveAll方法正常应该返回Page<Entity>类型对象,但你当前Mock返回的是List集合:后续控制器内调用page.getContent()遍历转换Dto时,就会因为List无法转为Page导致空指针。
解决方法:Mock返回Page类型对象,可用PageImpl构造:Mockito.when(myService.retrieveAll(anyInt(),anyInt())) .thenReturn(new PageImpl<>(objFactory.createRandomList()));ModelMapper未配置转换打桩逻辑
你用@MockBean注入了ModelMapper,Mock对象的所有方法默认返回null,如果控制器第48行是遍历Entity列表调用modelMapper.map(entity, Dto.class)做转换,拿到的返回值为null,后续操作该Dto对象就会触发空指针。
解决方法:给ModelMapper的转换方法打桩,或者直接注入真实的ModelMapper实例:// 打桩示例 Mockito.when(modelMapper.map(any(Entity.class), eq(Dto.class))) .thenReturn(new Dto(/* 构造参数 */));控制器方法参数缺少@RequestParam注解
如果你的控制器retrieveAll方法的pageNumber、pageSize参数没有添加@RequestParam注解,Spring MVC无法完成参数绑定,入参会直接为null,方法内直接使用就会触发空指针。
内容的提问来源于stack exchange,提问作者Lucho82

