티스토리 뷰

 

1. 사건 발달

스프링 시큐리티 환경에서 MVC를 테스트하기 위해서는 요청 헤더에 CSRF 토큰이 필요하다. 따라서 아래 코드와 같이 perform() 시에 요청 헤더에 스프링 시큐리티가 생성한 CSRF 토큰을 포함할 수 있다.

근데 테스트 코드를 작성할 때마다 CSRF 토큰을 일일이 추가하는 것보단, 테스트 실행 전에 자동으로 추가할 수 있지 않을까? 

@WithMockUser
@WebMvcTest(controllers = SectionController.class)
class SectionControllerTest {
    @Test
    @DisplayName("신규 회고카드를 등록한다.")
    void createSection() throws Exception {
        //given
        CreateSectionRequest request = CreateSectionRequest.builder()
            .retrospectiveId(1L)
            .templateSectionId(2L)
            .sectionContent("내용")
            .build();

        //when //then
        mockMvc.perform(
                post("/sections")
                    .content(objectMapper.writeValueAsString(request))
                    .contentType(APPLICATION_JSON)
                    .with(csrf())
            )
            .andDo(print())
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.code").value("201"))
            .andExpect(jsonPath("$.message").doesNotExist());
    }
}

 

 

2. 요청 헤더에 CSRF 토큰 자동으로 추가하기

@BeforeEachJUnit5에서 제공하는 애너테이션으로, 각 테스트가 실행되기 전에 호출된다. 이 애너테이션을 사용하여 모든 테스트가 실행되기 전에 CSRF 토큰을 추가하도록 해보자.

  • (1) MockMvcBuildersMockMvc 객체를 생성할 때 사용되는 유틸리티 클래스이다.
  • (2) 실제 웹 애플리케이션 컨텍스트(WebApplicationContext)를 사용하여 MockMvc 객체를 생성한다.
    • WebApplicationContext는 테스트할 때, Spring의 실제 웹 애플리케이션 환경을 모방하기 위해 사용된다.
  • (3) Spring Security 설정을 MockMvc에 적용한다.
    • springSecurity()SecurityMockMvcConfigurers의 메서드로, Spring Security의 필터 체인이 MockMvc 요청에 대해 적용되도록 설정한다.
    • 실제 웹 애플리케이션에서처럼 인증, 인가, CSRF 보호 등의 보안 기능을 테스트할 수 있게 된다.
  • (4) POST 요청의 모든 엔드포인트에 대하여 CSRF 토큰을 자동으로 포함한다.
    • defaultRequest()는 모든 테스트에서 사용될 요청 정보를 설정한다. 
    • post(), get() 이런 식으로 HTTP 메서드를 지정할 수 있다.
      • ex) post("/**") : 모든 경로("/**")에 대해 POST 요청을 대상으로 설정을 수행한다.
@WithMockUser
@WebMvcTest(controllers = SectionController.class)
class SectionControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext applicationContext;

    @BeforeEach
    public void setUp() {
        mockMvc = MockMvcBuilders  // (1)
            .webAppContextSetup(applicationContext)  // (2)
            .apply(springSecurity())  // (3)
            .defaultRequest(post("/**").with(csrf()))  // (4)
            .build();
    }
    
}

 

3. 결론

@BeforeEach에서 MockMvc 설정을 통해 매번 테스트 코드에 with(csrf())를 수동으로 추가하는 번거로움을 줄일 수 있다. 

@WithMockUser
@WebMvcTest(controllers = SectionController.class)
class SectionControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext applicationContext;

    @Autowired
    private ObjectMapper objectMapper;

    @BeforeEach
    public void setUp() {
        mockMvc = MockMvcBuilders
            .webAppContextSetup(applicationContext)
            .apply(springSecurity())
            .defaultRequest(post("/**").with(csrf()))
            .build();
    }

    @Test
    @DisplayName("신규 회고카드를 등록한다.")
    void createSection() throws Exception {
        //given
        CreateSectionRequest request = CreateSectionRequest.builder()
            .retrospectiveId(1L)
            .templateSectionId(2L)
            .sectionContent("내용")
            .build();

        //when //then
        mockMvc.perform(
                post("/sections")
                    .content(objectMapper.writeValueAsString(request))
                    .contentType(APPLICATION_JSON)
            )
            .andDo(print())
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.code").value("201"))
            .andExpect(jsonPath("$.message").doesNotExist());
    }
}

 

Total
Today
Yesterday
최근에 올라온 글
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30