Spring Framework.

SpringBootTest vs WebMvcTest

PI.314 2022. 2. 6. 01:25

@SpringBootTest 는 기본 구성 클래스를 찾고 Spring Application Context를 시작하도록 명령한다.

@SpringBootTest
public class SmokeTest {

	@Autowired
	private HomeController controller;

	@Test
	public void contextLoads() throws Exception {
		assertThat(controller).isNotNull();
	}
}

 

HomeController는 @Autowired를 통해 테스트 메소드가 실행되기전에 의존성을 주입받는다.

Spring Test의 좋은 기능은 Application Context가 테스트 간에 캐시된다는 것이다. 그렇게 하면 테스트 케이스에 여러 메소드가 있거나 동일한 구성의 여러 테스트 케이스가 있는 경우 애플리케이션을 한 번만 시작하는 비용이 발생한다. (@DirtiesContext 주석을 사용하여 캐시를 제어할 수 있다.)

 
애플리케이션이 실행이되면 다음과 같이 HTTP 요청을 보내고 응답을 받을 수 있다.
@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");
	}
}

webEnvironment=RANDOM_PORT를 사용하여 임의의 포트로 서버를 시작하고(테스트 환경에서 충돌을 방지하는 데 유용함) @LocalServerPort로 포트 정보를 주입한다.

위 예제는 Spring Boot가 제공하는 TestRestTemplate을 사용했다. 이번에는 @AutoConfigureMockMvc와 MockMvc를 사용하여 서버를 기동하지 않고 테스트하는 방법을 살펴보자. 여기에서 Spring은 들어오는 HTTP 요청을 처리하고 컨트롤러에 전달한다. 그렇게 되면 서버 시작 비용 없이 실제 HTTP 요청을 처리하는 것과 똑같은 방식으로 코드가 호출된다.

@SpringBootTest
@AutoConfigureMockMvc
public class TestingWebApplicationTest {

	@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")));
	}
}

 

이렇게 서버 없이도 전체 Spring Application Context를 실행하여 테스트를 진행할 수 있다.
 
@AutoConfigureMockMvc는 전체 Spring Application Context를 실행하기 때문에 Controller 뿐 만 아니라 테스트 대상이 아닌 @Service @Repository 에 해당하는 객체들도 모두 메모리에 사용된다.
 
그러면 테스트 대상인 Controller만 테스트 할 수 있는 방법은 없을까?
 
 
@WebMvcTest를 사용하면 테스트 범위를 Controller로 좁혀 테스트를 진행할 수 있다.
@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")));
	}
}

@WebMvcTest 특징

  • @Controller, @RestController가 설정된 클래스들을 찾아 메모리에 생성한다. 
  • @Service나 @Repository가 붙은 객체들은 테스트 대상이 아닌 것으로 처리되기 때문에 생성되지 않는다.
  • @WebMvcTest가 설정된 테스트 케이스에서는 서블릿 컨테이너를 모킹한 MockMvc타입의 객체를 목업하여 컨트롤러에 대한 테스트코드를 작성할 수 있다.
  • @WebMvcTest 어노테이션을 사용하면 MVC 관련 설정인 @Controller, @ControllerAdvice, @JsonComponent와 Filter, WebMvcConfigurer,  HandlerMethodArgumentResolver만 로드되기 때문에, 실제 구동되는 애플리케이션과 똑같이 컨텍스트를 로드하는 @SpringBootTest 어노테이션보다 가볍게 테스트 할 수 있다.

 

 

Testing the Web Layer

this guide is designed to get you productive as quickly as possible and using the latest Spring project releases and techniques as recommended by the Spring team

spring.io