본 글은 백기선님의 스프링부트 개념과 활용강좌를 수강하며 정리한 내용입니다.

그동안 테스트코드를 작성하는 것에 대한 막연함이 있었는데, 이번 포스트를 통해 효율적으로 mvc패턴에 대한 테스트를 진행할 수 있는 방법에 대해 정리한다.

먼저 테스트를 위해서 다음과 같은 의존성주입이 선행되어야한다 .

테스트를 위한 의존성 주입

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>


MockMvc 클라이언트 활용하기

해당 방법은 내장톰캣을 구동하지 않고 테스트하는 방식이다.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) // 서블릿 컨테이너를 테스트용으로 띄우지 않고 테스트 가능
@AutoConfigureMockMvc
public class SampleControllerTest {

    @Autowired
    MockMvc mockMvc;

        @Test
        public void hello() throws Exception {

             mockMvc.perform(get("/hello"))
            .andExpect(status().isOk()) //MockMvcResultMatchers에서 임폴트
            .andExpect(content().string("hello minsik"))
            .andDo(print());

        }

위와같은 방식으로 URL요청을 실제로 보내어 테스트를 할 수 있다. 프린트 되어 나온 결과는 다음과 같다.

MockHttpServletRequest:
  HTTP Method = GET
  Request URI = /hello
   Parameters = {}
      Headers = {}
         Body = null
Session Attrs = {}

Handler:
            Type = web.ecoveloper.sample.SampleController
        Method = public java.lang.String web.ecoveloper.sample.SampleController.hello()

Async:
    Async started = false
    Async result = null

Resolved Exception:
            Type = null

ModelAndView:
        View name = null
            View = null
            Model = null

FlashMap:
    Attributes = null

MockHttpServletResponse:
        Status = 200
    Error message = null
        Headers = {Content-Type=[text/plain;charset=UTF-8], Content-Length=[12]}
    Content type = text/plain;charset=UTF-8
            Body = hello minsik
    Forwarded URL = null
Redirected URL = null
        Cookies = []

이곳에 있는 거의 모든 값들에 대하여 테스트 Assertion을 실행할 수 있다.

Servlet 컨테이너를 띄워 테스트하기 1) restTemplate활용

@SpringBootTest의 설정을 Random Port로 변경해주면 실제 서블릿 컨테이너를 띄워 테스트를 진행할 수 있으며, 그 중 하나인 restTemplate를 활용해 본다.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest2 {

    @Autowired
    TestRestTemplate testRestTemplate;

    @MockBean // 실제 서블릿 컨테이너의 빈객체를 Mocking이 가능한 테스트용 빈객체로 교체할 수 있다.
    SampleService mockSampleService;

    @Test
    public void hello() throws Exception {
        when(mockSampleService.getName()).thenReturn("ecovel");

        String result = testRestTemplate.getForObject("/hello", String.class);
        Assert.assertThat(result, Matchers.is("hello ecovel") );
    }
}

WebTestClient 활용하기

WebTestClient를 활용하기 위해서는 다음과 같은 디펜던시를 추가해주어야 한다. WebTestClient는 restTemplate와 달리 Asyncronous한 형태로 활용할 수 있다.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux </artifactId>
    </dependency>

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class SampleControllerTest3 {

    @Autowired
    WebTestClient webTestClient;

    @MockBean
    SampleService mockSampleService;

    @Test
    public void hello() throws Exception {

        when(mockSampleService.getName()).thenReturn("ecoveloper");
        webTestClient.get().uri("/hello").exchange()
                .expectStatus().isOk()
                .expectBody(String.class).isEqualTo("hello ecoveloper");
    }
}