SMALL

@WebMvcTest 어노테이션은 Controller Layer를 테스트할 때 사용된다.

( https://joomn11.tistory.com/86 )

 

해당 어노테이션을 사용하면 Spring MVC 컨트롤러를 이용한 요청과 응답에 필요한 Bean들만 로딩하여 가벼운 테스트 환경을 제공한다. 

 

@WebMvcTest 어노테이션을 사용시 다음 내용만 스캔하도록 제한한다

@Controller,
@ControllerAdvice,
@JsonComponent,
Converter / GenericConverter,
Filter,
WebSecurityConfigurerAdapter,
WebMvcConfigurer,
HandlerMethodArgumentResolver

@Component, @Service or @Repository  Bean들은 스캔에서 제외된다. 

 

Spring Security에 대한 설정은 @WebMvcTest의 스캔 대상에 해당한다. 

하지만, 대부분의 Spring Security에서는 다른 Bean들에 대한 Dependency가 존재하게 된다.

@RequiredArgsConstructor
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomOAuth2UserService customOAuth2UserService; // Dependency!!

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	
        http.csrf().disable().headers().frameOptions().disable()
                .and().authorizeRequests() 
                .antMatchers("/", "/css/**", "/js/**", "h2-console/**").permitAll()
                .antMatchers("/api/**").hasRole(Role.USER.name()).anyRequest().authenticated() 
                .and().logout().logoutSuccessUrl("/") 
                .and().oauth2Login() 
                .userInfoEndpoint() 
                .userService(customOAuth2UserService); 

    	http.csrf().disable().headers().frameOptions()
    	    	.disable().and().authorizeRequests().anyRequest().permitAll();
    }

}

 

그렇기 때문에  @WebMvcTest를 진행할 경우 아래와 같은 에러를 보게 된다.

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '${classInfo}' available: expected at least 1 bean which qualifies as autowire candidate.

 

해당 문제를 해결하기 위해서는 Controller Layer에 해당하는 내용에만 Test를 집중할 수 있도록 WebSecurityConfigurerAdapter를 스캔 대상에서 제외하고 @WithMockUser를 통해 Mock 인증 사용자를 생성한다.

 

@WebMvcTest(controllers = HelloController.class, 
        excludeFilters = { //!Added!
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class) })
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    @WithMockUser(roles = "USER") //!Added!
    public void hello가_리턴된다() throws Exception {
        String hello = "hello";
        mvc.perform(get("/hello")).andExpect(status().isOk()).andExpect(content().string(hello));
    }

}
LIST

+ Recent posts