Kotlin

[Spring Boot 3.0 / Spring Security 6.0] Controller에서 시큐리티 인증 mocking 후 테스트 하기(401 피하기)

keep it simple 2024. 1. 11. 16:57

문제

  • 스프링 부트 3.2 / Spring Security 6.0 적용을 한 후 유저가 모임을 생성하는 API를 테스트 해야된다. 하지만 애석하게도 인증 실패로 401이 반환된다. 

주어진 상황

설정된 스프링 시큐리티 

  • 밑과 같이 http.authorizedHttpRequests 안에 permitAll()된 엔드포인트들만 인증을 안해도 접근이 가능한다. 이 외에 모든 엔드포인트에는 인증이 필요하다.
@Bean
fun securityFilterChain(
    http: HttpSecurity,
    jwtAuthenticationFilter: JwtAuthenticationFilter,
): DefaultSecurityFilterChain {
    http
        .csrf { it.disable() }
        .headers { it.frameOptions { frame -> frame.disable() } }
        .formLogin { it.disable() }
        .httpBasic { it.disable() }
        .authorizeHttpRequests {
            it
                .requestMatchers("/api/auth", "/swagger-ui/**", "/v3/api-docs/**", "/error")
                .permitAll()

            it
                .anyRequest()
                .authenticated()
        }
        .sessionManagement {
            it.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        }
        .authenticationProvider(authenticationProvider)
        .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java)
        .exceptionHandling {
            it.authenticationEntryPoint(customAuthenticationEntryPoint)
        }

 

테스트코드

  • 밑에 api/v1/gatherings는 인증이 필요한 엔드포인트다. 
class CrewControllerTest : ControllerSupport() {

    @MockBean
    private lateinit var crewRepository: CrewRepository

    @MockBean
    private lateinit var crewService: CrewService

    @Test
    @DisplayName("모임을 등록한다.")
    fun createCrew() {
        // given
        val createRequest = createCrewRequest()

        // when
        val apiStatus = performPost("/api/v1/gatherings", createRequest)
        val successStatus = 200

        // then
        assertEquals(apiStatus, successStatus)
    }
}

 

테스트 작동시 밑과 같은 테스트 실패가 나온다. 

어떻게 해결할까? 

  • 인증만 모킹할 경우에는 스프링 시큐리티 테스트 패키지에서 제공하는 @WithMockUser 를 사용하면 된다.(밑에는 해당 어노테이션 내부 코드다.)
  • 어노테이션 내부 코드를 보면 기본값으로 유저 value는 user이고 권한도 USER이다.

  • 만약 특정 유저이름과 특정 유저 권한으로 테스트하고싶을 경우에는 밑과 같이 어노테이션안에 필드 값 채워준 후 테스트하면 된다. 
@Test
@DisplayName("크루를 등록한다.")
@WithMockUser(username = "testUser", roles = ["ADMIN"])
fun createCrew() {
    // given
    val createRequest = createCrewRequest()

    // when
    val apiStatus = performPost("/api/v1/crews", createRequest)
    val successStatus = 200

    // then
    assertEquals(apiStatus, successStatus)
}

성공 테스트 케이스

Reference