I've an issue while running unit tests for REST controllers using WebMvcTest annotation.
It's important to mention that I don't want to bootstrap the whole context using the annotation @SpringBootTest. I want to make it work with @WebMvcTest.
Here is the test class:
@Import(SecurityConfig.class)
@WebMvcTest(controllers = SomeController.class)
class SomeControllerTest {
private static final String BASE_URL = "/api/something";
@Autowired
private MockMvc mockMvc;
@MockBean
private SomeService someService;
@Test
void shouldReturnNoContent() throws Exception {
doNothing().when(pauseJobUseCase).pause(anyString());
mockMvc.perform(put(BASE_URL, anyString())).andExpect(status().isNoContent());
}
}
and here is the Security Configuration:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Value("${security.username}")
private String username;
@Value("${security.password}")
private String password;
@Bean
@Order(1)
public SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.securityMatcher(AntPathRequestMatcher.antMatcher("/api/app/**"))
.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.sessionManagement(
session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.httpBasic(withDefaults()) // Do not use in production environment!
.build();
}
@Bean
@Order(2)
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.securityMatcher("/api/auth/**", "/api/admin/**")
.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.headers(headers -> headers.frameOptions(FrameOptionsConfig::disable))
.sessionManagement(
session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(
authorize -> authorize
.requestMatchers("/api-docs/**", "/scheduler-saas.html", "/swagger-ui/**").permitAll()
// will be handled on controller level (pre-authorized)
.requestMatchers("/api/auth/**").permitAll()
// "Open" API (requires correct credentials)
.requestMatchers("/api/admin/**").permitAll()
.anyRequest().authenticated()
)
.build();
}
@Bean
@Order(3)
public SecurityFilterChain jwtSecurityFilterChain(HttpSecurity http, JwtFilter jwtFilter)
throws Exception {
return http
.securityMatcher("/api/job/**")
.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.headers(headers -> headers.frameOptions(FrameOptionsConfig::disable))
.sessionManagement(
session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder)
{
var userDetails = User.builder()
.username(username)
.password(passwordEncoder.encode(password))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
public record AccessViolationResponse(String message, String localizedMessage) {
}
}
The error I'm getting is the following:
No qualifying bean of type 'com.hedza06.saasscheduler.security.jwt.JwtTokenProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I've read this GitHub issue but it wasn't helpful.
The tech stack I'm using is the following:
- Java 21
- Spring Boot 3.1.4
- Spring Security Core [6.1.4]
Any ideas how to solve this issue?