移除WebSecurityConfigurerAdapter后WebMvcTest失效,测试报错求助
升级Spring Security配置、替换已弃用的WebSecurityConfigurerAdapter后,应用通过Postman测试运行正常,但大量标注@WebMvcTest的测试用例报错,以下是典型问题及解决办法:
错误1:AuthTokenFilterTest抛出UnsatisfiedDependencyException
错误栈核心信息:
UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.security.AuthTokenFilterTest': Unsatisfied dependency expressed through field 'authTokenFilter'; nested exception is NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.security.AuthTokenFilter' available: expected at least 1 bean which qualifies as autowire candidate.
测试代码片段:
@WebMvcTest(AuthTokenFilter.class) public class AuthTokenFilterTest { @Autowired private AuthTokenFilter authTokenFilter; // 测试逻辑... }
错误2:RegisterControllerTest中AuthController创建失败
错误栈核心信息:
UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.controller.AuthController': Unsatisfied dependency expressed through field 'passwordEncoder'; nested exception is NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.crypto.password.PasswordEncoder' available: expected at least 1 bean which qualifies as autowire candidate.
测试代码片段:
@WebMvcTest(RegisterController.class) public class RegisterControllerTest { @Autowired private MockMvc mockMvc; // 测试逻辑... }
新旧SecurityConfig代码对比
旧配置(基于WebSecurityConfigurerAdapter)
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Bean public AuthTokenFilter authenticationJwtTokenFilter() { return new AuthTokenFilter(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { // 原有HttpSecurity配置 } }
新配置(替换WebSecurityConfigurerAdapter)
@Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private UserDetailsServiceImpl userDetailsService; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() ); http.authenticationProvider(authenticationProvider()); http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public AuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userDetailsService); authProvider.setPasswordEncoder(passwordEncoder()); return authProvider; } // 问题点:私有方法未声明为Bean private AuthTokenFilter authenticationJwtTokenFilter() { return new AuthTokenFilter(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
问题原因及解决方案
针对错误1:AuthTokenFilter无法被注入
原因:新配置中authenticationJwtTokenFilter()是私有方法,且未添加@Bean注解,导致Spring容器中没有该类型的Bean实例,测试类无法自动注入。
解决办法:将该方法改为公共方法并添加@Bean注解:
@Bean public AuthTokenFilter authenticationJwtTokenFilter() { return new AuthTokenFilter(); }
针对错误2:PasswordEncoder无法被注入到AuthController
原因:@WebMvcTest注解默认只会加载控制器层相关的Bean,不会自动加载Security配置类中的Bean。如果AuthController依赖PasswordEncoder,测试环境中就会缺少该Bean。
解决办法二选一:
- 在测试类中手动声明
PasswordEncoderBean:
@WebMvcTest(RegisterController.class) public class RegisterControllerTest { @Autowired private MockMvc mockMvc; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 测试逻辑... }
- 在测试类中通过
@Import引入SecurityConfig:
@WebMvcTest(RegisterController.class) @Import(SecurityConfig.class) public class RegisterControllerTest { @Autowired private MockMvc mockMvc; // 测试逻辑... }
如果只需要PasswordEncoder,也可以单独导入包含该Bean的配置类,避免加载不必要的Security组件。
内容的提问来源于stack exchange,提问作者sineverba

