web/Spring

Spring Application Test 정리

반응형

Spring에서 Junit을 통해 테스트하는데 익숙해져있다. 

이 방식과 더불어서 Spring의 MockMvc를 이용하여 Web Layer를 테스트 하는 방법에 대해 공부해보자. 

우선 테스트를 진행하기 위해서 Spring-boot-starter-test를 추가해야한다. 

Gradle

1
testCompile("org.springframework.boot:spring-boot-starter-test")
cs


그러면 테스트 클래스 파일에 @SpringBootTest와 @RunWith가 추가된다.  
@SpringBootTest는 Spring Boot에서 주 구성 클래스를 찾아서 Spring Application Context를 시작하도록 하는 어노테이션이다. 

Controller 테스트를 진행할 떄 서버를 가동시키고 TestRestTemplate를 사용하여 테스트를 진행할 수 있다.

TestRestTemplate를 이용한 web layer 테스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class HttpRequestTest {
 
    @LocalServerPort
    private int port;
 
    @Autowired
    private TestRestTemplate restTemplate;
 
    @Test
    public void greetingShouldReturnDefaultMessage() throws Exception {
        assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/",
                String.class)).contains("Hello World");
    }
}
cs

하지만 서버 실행하고 테스트를 진행하면 너무 비용이 크기 때문에 이런 비용을 없에기 위해서 MockMvc를 사용할 수 있다. 

MockMvc를 이용한 테스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ApplicationTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @Test
    public void shouldReturnDefaultMessage() throws Exception {
        this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().string(containsString("Hello World")));
    }
}
cs

하지만 위와같은 방식은 모든 Spring application의 context가 실행 되었기 때문에 단순히 web layer만을 사용하여 테스트 하고 싶은 경우에 @WebMvcTest 애노테이션을 설정하여 간단하게 테스트를 진행할 수 있다.


WebMvcTest 애노테이션을 이용한 테스트

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringRunner.class)
@WebMvcTest
public class WebLayerTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @Test
    public void shouldReturnDefaultMessage() throws Exception {
        this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().string(containsString("Hello World")));
    }
}
cs

방식은 모두 같지만 모든 context를 로드하지 않고 web layer만 로드하기에 비용이 더저렴하다. 

또한 컨트롤러에서 의존주입한 서비스는 @MockBean 어노테이션을 사용하여 inject 하여 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RunWith(SpringRunner.class)
@WebMvcTest(GreetingController.class)
public class WebMockTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @MockBean
    private GreetingService service;
 
    @Test
    public void greetingShouldReturnMessageFromService() throws Exception {
        when(service.greet()).thenReturn("Hello Mock");
        this.mockMvc.perform(get("/greeting")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().string(containsString("Hello Mock")));
    }
}
cs

위의 코드에 보면 GreetingService에 경우 GreetingController에서 주입되는 Bean이기 때문에 @MockBean 형태로 가지고와서 Mockito 형태로 사용할 수 있다.

Spring에서 단위 테스트를 할 수 있는 방식은 많다. 조금 더 비용을 줄이고 효율적으로 테스트 할 수 있는 방법을 알고 사용해보자!

반응형