Controller单元测试执行MockMvc时出现NullPointerException问题
解决Controller单元测试中的NullPointerException问题
问题根源分析
你的测试报错是因为Controller里的userService实例为null,同时代码里还有几个关键错误:
- 静态方法调用错误:Controller的
getUsersForList方法里写的是UserService.getUsersForList()(大写U),这是调用静态方法,但你的getUsersForList应该是实例方法,必须用成员变量userService(小写u)调用 - Service实例化方式错误:Controller构造函数里手动
new UserService(...),没有通过Spring依赖注入,导致测试中用@MockBean创建的UserService mock对象无法替换掉Controller里自己new的实例 - 测试类缺少必要注解:
@AutoConfigureMockMvc需要配合@SpringBootTest才能启动Spring上下文,否则MockBean和MockMvc都无法正常工作 - 类型拼写错误:Controller方法返回的是
List<UserData>,但你写的是List<UsersData>,多了个s,会导致编译错误
修复后的Controller代码
@RestController @CrossOrigin @RequestMapping("/api/users") public class UserMigrationController { private final UserService userService; @Value("${SOURCE_DNS}") private String sourceDns; // 推荐用构造注入,让Spring管理UserService实例 @Autowired public UserMigrationController(UserService userService) { this.userService = userService; } @GetMapping(value = "/getUsers", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<UserData>> getUsersForList() throws Exception { // 修正为实例方法调用,同时修正泛型类型 List<UserData> usersDataList = userService.getUsersForList(); return new ResponseEntity<>(usersDataList, HttpStatus.OK); } }
修复后的测试类代码
@SpringBootTest @AutoConfigureMockMvc class UserMigrationControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; // 去掉不必要的MockitoAnnotations.openMocks(this),@MockBean由Spring自动处理 @Test void should_get_users_for_list() throws Exception { String id = "id"; String name = "name"; UserData userData = new UserData(id, name); List<UserData> response = new ArrayList<>(); response.add(userData); // 这里mock的是实例方法,符合修复后的Controller调用逻辑 when(userService.getUsersForList()).thenReturn(response); mockMvc.perform(MockMvcRequestBuilders.get("/api/users/getUsers") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.status().isOk()); } }
额外说明
- 构造注入是Spring官方推荐的依赖注入方式,它能保证依赖不可变,同时方便单元测试
@MockBean会自动替换Spring上下文中对应的真实Bean,所以必须让Controller通过Spring注入UserService,而不是自己new- 测试类里的
@SpringBootTest会启动完整的Spring上下文,配合@AutoConfigureMockMvc可以轻松测试Controller的HTTP请求
内容的提问来源于stack exchange,提问作者pussyCat
相关产品推荐
相关产品推荐

