Spring Boot @WebMvcTest使用@WithUserDetails出现空指针问题求助
问题分析与解决方案
这个空指针问题的核心原因是**@WithUserDetails的执行时机早于你在测试方法中设置的Mock返回值**。
当Spring Security的WithSecurityContextTestExecutionListener在测试方法执行前(也就是beforeTestMethod阶段)创建SecurityContext时,会调用你Mock的userDetailsService.loadUserByUsername,但此时你在testSaveBackground方法里写的given(userDetailsService.loadUserByUsername(...)).willReturn(...)还没有执行,所以loadUserByUsername返回null,进而触发空指针异常。
解决步骤
1. 将Mock Stubbing移至@Before方法
把初始化userDetailsService返回值的代码移到测试类的@Before方法中,确保在@WithUserDetails执行前就完成Stubbing:
@RunWith(SpringRunner.class) @WebMvcTest(PDPController.class) @AutoConfigureMockMvc(addFilters = false) public class PDPControllerTests { @Autowired private MockMvc mvc; @Autowired private ObjectMapper objectMapper; @MockBean private PDPService pdpService; @MockBean(name = "userDetailsService") private MyUserDetailsService userDetailsService; private Account account; private Employee employee; @Before public void setUp() { account = new Account(); employee = new Employee(); // 提前设置userDetailsService的返回值,确保@WithUserDetails调用时能拿到对象 given(userDetailsService.loadUserByUsername(anyString())).willReturn(new EmployeeDetails(employee, account)); } @Test @WithUserDetails(value = "someemail@email.com", userDetailsServiceBeanName = "userDetailsService") public void testSaveBackground_returns_result_from_service() throws Exception { PersonalDevelopmentPlan pdp = new PersonalDevelopmentPlan(); pdp.setEmployee(EMPLOYEE_ID); given(pdpService.saveBackground(eq(EMPLOYEE_ID), any(), anyInt())).willReturn(pdp); mvc.perform(patch(URL_WITH_ID + "/background").secure(true) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(pdp))) .andExpect(status().isOk()) .andExpect(jsonPath("$.employee", Matchers.is(EMPLOYEE_ID))); } }
2. 额外检查项
- 确认你的
EmployeeDetails构造方法不会因为传入的employee或account为空而触发内部空指针(比如如果构造方法里直接访问employee.getId()但employee未初始化的话)。可以给employee和account设置必要的属性,比如:employee.setId(EMPLOYEE_ID); account.setEmail("someemail@email.com"); - 确保
@MockBean(name = "userDetailsService")的名称和@WithUserDetails中指定的userDetailsServiceBeanName完全一致,避免Spring找不到对应的Bean。
内容的提问来源于stack exchange,提问作者Kars
相关产品推荐
相关产品推荐

