@SpringBootTest 컨텍스트 캐싱

컨텍스트 캐싱

스프링 프레임워크를 사용해 개발된 애플리케이션은 구동할 때 필요한 것들을 미리 준비하는 시간이 소요됩니다. 따라서 통합 테스트를 위해 @SpringBootTest 애너테이션을 사용할 때도 준비 작업이 필요합니다.

실행해야 할 테스트가 10개 있을 때 각 테스트가 실행 될 때마다 매번 똑같은 준비 작업을 하는 것은 비효율적입니다.

만약 10개의 테스트를 실행하기 위한 준비 작업이 모두 동일하다면 한 번만 작업하고 10개의 테스트에 공통으로 사용하는 것이 합리적이겠죠.

Spring Test Context Framework에서는 이러한 동작 방식을 제공하고 있으며 Context Caching이라 합니다. (Context Management and Caching 👈click!! 공식 문서)

핵심 아이디어

SpringBoot 테스트 시 사용하는 컨텍스트를 재사용하기 위해서는 컨텍스트에 할당된 Bean 집합이 동일해야 합니다.

만약 테스트 클래스에서 @MockBean을 사용하여 Mock 객체를 Bean으로 주입 받는 경우 매번 객체를 새로 생성해서 주입하므로 Bean 집합이 동일하지 않기 때문에 컨텍스트를 재사용하지 않습니다. 매번 컨텍스트를 새로 생성하게 되어 전체 테스트가 매우 느려집니다.

공통으로 사용할 테스트 클래스를 하나 만들고 다른 테스트 클래스에서 상속 받아 사용하면 동일한 컨텍스트를 사용하게 할 수 있습니다.

컨텍스트를 초기화 하는 시간이 한 번만 소요되므로 테스트를 비교적 빠르게 실행할 수 있게 됩니다.

컨트롤러 테스트 코드 예시

테스트를 위해 두 개의 간단한 RestController를 작성해보겠습니다.

RestController 테스트 방법에 대해 간단히 정리했던 글이 있습니다.
필요하다면 참고하시기 바랍니다.
(RestController 테스트하기 (MockMvc) 👈click!!)

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ColorController {

  @GetMapping("/color")
  public String color() {
    return "green";
  }

}
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FruitController {

  @GetMapping("/fruit")
  public String fruit() {
    return "banana";
  }

}

이제 컨트롤러 테스트에서 공통적으로 사용할 수 있는 ControllerTest 클래스를 작성합니다.

import com.targetcoders.blogtest.controller.ColorController;
import com.targetcoders.blogtest.controller.FruitController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;


@AutoConfigureMockMvc
@SpringBootTest(classes = {ColorController.class, FruitController.class})
public class ControllerTest {

  @Autowired
  protected MockMvc mockMvc;

}

FoodController와 FruitController를 Bean으로 등록한 TestContext를 공유하여 사용하기 위해서

아래와 같이 ControllerTest를 상속 받아 사용할 수 있습니다.

import com.targetcoders.common.ControllerTest;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

public class ColorControllerTest extends ControllerTest {

  @Test
  void colorTest() throws Exception {
    mockMvc.perform(MockMvcRequestBuilders.get("/color"))
        .andExpect(MockMvcResultMatchers.content().string("red"));
  }

}
import com.targetcoders.common.ControllerTest;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

public class FruitControllerTest extends ControllerTest {

  @Test
  void fruitTest() throws Exception {
    mockMvc.perform(MockMvcRequestBuilders.get("/fruit"))
        .andExpect(MockMvcResultMatchers.content().string("banana"));
  }

}
스스로 경험하며 얻은 깨달음을 공유하기 좋아하며, 세상이 필요로 하는 코드를 작성하기 위해 노력하는 개발자입니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다