WebMvcTest测试疑问:从WebSecurityConfigurerAdapter迁移至SecurityFilterChain后@WithMockUser测试失效
这个问题其实很常见——当你切换到Spring Security的组件式配置(SecurityFilterChain + UserDetailsManager Bean)后,@WebMvcTest 默认不会自动加载这些安全相关的Bean,导致@WithMockUser无法生效,最终返回401未授权。
为什么旧配置能正常工作?
旧的WebSecurityConfigurerAdapter配置类上标注了@EnableWebSecurity,这个注解会触发Spring Security的自动配置逻辑,而@WebMvcTest在默认情况下会扫描并加载带有@EnableWebSecurity的配置类,所以你的测试能拿到正确的安全上下文,@WithMockUser也就正常生效了。
而新的组件式配置只是单独定义了SecurityFilterChain和InMemoryUserDetailsManager Bean,没有触发自动配置的注解,@WebMvcTest作为一个专注于MVC层的测试切片,默认不会加载用户自定义的这些Bean,所以测试上下文里没有安全过滤链,@WithMockUser的模拟用户信息也无法被识别,自然就返回401了。
修复方案
最简单的解决办法就是在你的@WebMvcTest测试类里显式导入安全配置类,让测试上下文加载必要的安全Bean:
@WebMvcTest(TestController.class) @Import(SecurityConfiguration.class) // 加上这一行 class TestControllerTest { @Autowired private MockMvc mockMvc; @Test @WithMockUser(username = "user", roles = {"USER"}) void givenMockedCredentials_shouldAccessSecuredEndpoint() throws Exception { mockMvc.perform(get("/secured")) .andExpect(status().isOk()) .andExpect(content().string("Hello secured world!")); } // 其他测试方法... }
这样修改后,测试会加载你的SecurityConfiguration类中的SecurityFilterChain和InMemoryUserDetailsManager Bean,@WithMockUser就能正确模拟授权用户,测试也就会返回200状态码了。
另外,如果你不想导入整个配置类,也可以单独定义测试专用的安全配置Bean,然后通过@Import导入,但对于大部分场景来说,直接导入生产用的安全配置是最直接的方式。
内容的提问来源于stack exchange,提问作者pszemus

