본문으로 바로가기

[Spring] Security 가 적용된 Test

category Framework/Spring 2022. 1. 14. 17:55

1. Dependency

// bundle.gradle
dependencies {
	// ...
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
  	testImplementation 'org.springframework.security:spring-security-test'
	// ...
}
  • spring-boot-starter-test : JUnit 을 포함해 테스트에 요구되는 기본 패키지들을 포함한다.
  • spring-security-test : Spring Security 가 적용된 경우 테스트를 위한 Security Context 를 생성할 수 있는 어노테이션 패키지를 제공한다.

 

2. 단위 테스트 작성 시 오류가 발생하는 경우

더보기

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException

 

Error creating bean with name 'securityConfig' defined in file .......

@SpringBootTest 와 같이 IoC 컨테이너를 모두 포함하는 통합테스트가 아닌 @WebMvcTest 와 같은 슬라이스(단위) 테스트를 진행하는 경우 해당 Layer 에서 필요로 하는 의존성이 주입되지 않아 테스트 코드 실행이 불가하다. 

이럴 경우 아래의 2가지 방법을 통해 해결이 가능하다.

2.1 테스트에 필요한 의존성을 @MockBean 을 통해 주입해주는 방법

@ActiveProfiles("test")
@WebMvcTest(
        controllers = IndexController.class
)
class IndexControllerTest {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private WebApplicationContext context;

	// Security 적용에 필요한 의존객체 생성
    @MockBean
    TokenProvider tokenProvider;

	// Security 적용에 필요한 의존객체 생성
    @MockBean
    JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

	// Security 적용에 필요한 의존객체 생성
    @MockBean
    JwtAccessDeniedHandler jwtAccessDeniedHandler;

    @BeforeEach
    void setUp() {
        // 응답결과 인코딩 설정
        this.mvc = MockMvcBuilders.webAppContextSetup(context)
                .addFilter(new CharacterEncodingFilter("UTF-8", true))
                .alwaysDo(print())
                .build();
    }

    @Test
    void index() throws Exception {
        mvc.perform(get("/"))
                .andExpect(status().is3xxRedirection())
                .andExpect(status().isSeeOther())
                .andDo(print());
    }
}

 

2.2 @WebMvcTest 어노테이션의 excludeFilters 프로퍼티를 통해 해당 의존성을 제외 하는 방법

@ActiveProfiles("test")
@WebMvcTest(
        controllers = IndexController.class
        // 테스트를 위해 요구되는 SeurityConfig.class 를 제외하고 실행
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class),
        }
)
class IndexControllerTest {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    void setUp() {
        // 응답결과 인코딩 설정
        this.mvc = MockMvcBuilders.webAppContextSetup(context)
                .addFilter(new CharacterEncodingFilter("UTF-8", true))
                .alwaysDo(print())
                .build();
    }

    @Test
    void index() throws Exception {
        mvc.perform(get("/"))
                .andExpect(status().is3xxRedirection())
                .andExpect(status().isSeeOther())
                .andDo(print());
    }
}

이 방법을 사용하는 경우 Security 에 적용된 @PreAuthorize 등의 권한 검증은 할 수가 없으므로 2.1 방법을 사용하는 것이 정확한 테스트를 위해 더 좋은 방법으로 판단된다.

'Framework > Spring' 카테고리의 다른 글

[Spring] Lifecycle  (0) 2022.01.15
[Spring] 00. Spring Triangle 스프링의 핵심 3대 요소  (0) 2022.01.14
[Spring] Open API 3 (with Swagger3)  (0) 2022.01.11
[Spring] Swagger 3  (0) 2022.01.11
[Spring] Filter & Interceptor  (0) 2021.12.22