Spring Boot 3控制器层单元测试:认证环节空指针异常
问题分析与解决方案
空指针异常原因
- 测试环境默认
spring.security.enabled=false,此时WebSecurityConfig中的认证逻辑未生效,即使添加@WithMockUser注解,请求也不会被Spring Security处理,导致控制器方法的Principal参数为null。 getUserInfo方法未对Principal为null的情况做校验,直接进行类型强转,触发空指针异常。
解决方案
方案一:测试时启用Security配置
在测试类上添加属性配置,强制开启Security,让@WithMockUser能正常注入认证信息:
@ExtendWith(MockitoExtension.class) @WebMvcTest(SMVConfigController.class) @TestPropertySource(properties = "spring.security.enabled=true") // 新增该行 class SMVConfigControllerTest { // 原有测试代码保持不变 }
方案二:完善控制器空指针防护
在getUserInfo方法中先判断Principal是否为null,避免空指针:
private UserInfo getUserInfo(Principal principal){ if(principal == null){ // 根据业务需求处理:返回默认匿名用户或抛出异常 return UserInfo.builder().username("anonymous").build(); // 也可抛出异常:throw new IllegalAccessException("请求未完成认证"); } if(principal instanceof JwtAuthenticationToken) { return userInfoHelper.getUserInfo(((JwtAuthenticationToken) principal).getToken().getTokenValue()); }else if(principal instanceof UsernamePasswordAuthenticationToken) { User user = (User)((UsernamePasswordAuthenticationToken) principal).getPrincipal(); return UserInfo.builder().username(user.getUsername()).build(); }else{ // 处理其他未知类型的Principal return UserInfo.builder().username("unknown").build(); } }
方案三:测试时手动注入认证信息
如果不想开启Security配置,可通过SecurityMockMvcRequestPostProcessors手动给请求添加认证对象:
@Test void addSmvConfigTest() throws Exception{ Gson gson = new GsonBuilder() .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()) .create(); SmvDTO smvDto = SmvConfigSampleData.createSampleDto(); // 构造测试用的认证对象 User testUser = new User("TEST_USER", "", Collections.emptyList()); UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(testUser, null, testUser.getAuthorities()); RequestBuilder addSmvConfigRequestBuilder = MockMvcRequestBuilders.post(basePath + "/") .contentType(MediaType.APPLICATION_JSON) .content(gson.toJson(smvDto)) .accept(MediaType.APPLICATION_JSON) .with(SecurityMockMvcRequestPostProcessors.authentication(authToken)); // 注入认证信息 when(smvConfigService.saveSmvConfig(any(), any())).thenReturn(SmvConfigSampleData.createSampleDto()); mockMvc.perform(addSmvConfigRequestBuilder).andExpect(status().isOk()); }
Postman测试说明
UsernamePasswordAuthenticationToken是Spring Security内部的认证对象,Postman无法直接发送。实际场景处理方式:
- 若
securityEnabled=true:通过OAuth2流程获取JWT Token,在请求头添加Authorization: Bearer <token>,控制器会自动接收JwtAuthenticationToken类型的Principal。 - 若
securityEnabled=false:依赖控制器中对Principal为null的处理逻辑,或自定义请求头传递用户信息(仅用于临时测试)。
内容的提问来源于stack exchange,提问作者Saksham98
相关产品推荐
相关产品推荐

