[Spring Boot #10] 스프링 부트 테스트 (Spring Boot Test)
- 📚 Spring/Spring Boot
- 2020. 4. 29. 09:09
| 스프링 부트 테스트 (Test)
스프링부트에서는 @SpringBootTest 어노테이션을 통해 스프링부트 어플리케이션 테스트에 필요한 모든 의존성을 제공한다.
또한, @SpringBootTest 어노테이션 내에서 어떠한 테스트 환경으로 테스트를 할 것인지를 따로 지정할 수 있다.
스프링부트 테스트를 진행하기 위해서는 먼저 다음과같은 의존성을 추가해야 한다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
관련 코드
@RestController
public class SampleController {
@Autowired
private SampleService sampleService;
@GetMapping("/hello")
public String hello(){
return "hello " + sampleService.getName();
}
}
@Service
public class SampleService {
public String getName(){
return "younghwan";
}
}
@SpringBootApplication
public class SpringtestApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(SpringtestApplication.class);
application.run(args);
}
}
위의 내용들을 테스트 할 테스트 코드이다.
package me.kyhslam.springdemo.sample;
import org.junit.Test;
import org.junit.runner.RunWith;
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.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void hello() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("hello younghwan"))
.andDo(MockMvcResultHandlers.print());
}
}
- @RunWith 어노테이션은 JUnit 프레임워크가 테스트를 실행할 시 테스트 실행방법을 확장할 때 쓰는 어노테이션이다.
즉, JUnit 프레임워크가 내장된 Runner를 실행할 때 @Runner 어노테이션을 통해 SpringRunner.class라는 확장된 클래스를 실행하라고 지시하는 것이다. - @SpringBootTest는 스프링부트 어플리케이션 테스트 시 테스트에 필요한 거의 모든 의존성을 제공하는 어노테이션이다. @SpringBootApplication을 기준으로 스프링 빈을 등록함과 동시에 Maven과 같은 빌드 툴에 의해 추가된 스프링부트 의존성도 제공해 준다. @SpringBootTest 어노테이션에는 webEnvironment라는 값을 통해 웹 애플리케이션 테스트시 Mock으로 테스트할 것인지 톰캣과 같은 서블릿 컨테이너로 테스트할 것 인지를 정할 수 있다.
- @AutoConfigureMockMvc는 Mock 테스트 시 필요한 의존성을 제공해 준다.
- MockMvc 객체를 통해 실제 컨테이너가 실행되는 것은 아니지만 로직상으로 테스트 진행할 수 있다. (DispatcherServlet은 로딩되어 Mockup으로서 기능을 한다.)
- print() 함수를 통해 더 자세한 테스트 결과를 볼 수 있다.
MockHttpServletRequest:
HTTP Method = GET
Request URI = /hello
Parameters = {}
Headers = {}
Body = null
Session Attrs = {}
Handler:
Type = me.kyhslam.springdemo.sample.SampleController
Method = public java.lang.String me.kyhslam.springdemo.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=[15]}
Content type = text/plain;charset=UTF-8
Body = hello younghwan
Forwarded URL = null
Redirected URL = null
Cookies = []
| 서블릿 컨테이너 테스트
위에서 테스트한 Mockup을 통한 테스트가 아닌 실제 서블릿 컨테이너를 구동하여 테스트하는 방법이다. 즉, 내장 톰캣 서버에 요청을 보내 테스트를 하는 것이다. @SpringBootTest 어노테이션에 webEnvironment값을 변경해줘야 한다.
package me.kyhslam.springdemo.sample;
import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
@Autowired
TestRestTemplate testRestTemplate;
@Test
public void hello() throws Exception {
String result = testRestTemplate.getForObject("/hello", String.class);
Assertions.assertThat(result).isEqualTo("hello younghwan");
}
}
만약 서비스단 까지 가지않고 내가 원하는 컨트롤러만 테스트 하고 싶다면 SampleService를 이용하여 Mockup을 만들어 테스트 할 수 있다.
package me.kyhslam.springdemo.sample;
import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
@Autowired
TestRestTemplate testRestTemplate;
@MockBean
SampleService mockSampleService;
@Test
public void hello() throws Exception {
Mockito.when(mockSampleService.getName()).thenReturn("younghwan");
String result = testRestTemplate.getForObject("/hello", String.class);
Assertions.assertThat(result).isEqualTo("hello younghwan");
}
}
| WebTestClient 테스트
Spring에 새로 추가된 테스트로 웹 클라이언트를 통해서 비동기 형식으로 테스트를 할 수 있다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
WebTestClient를 이용하여 비동기 형식으로 테스트하는 코드이다.
package me.kyhslam.springdemo.sample;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
@Autowired
WebTestClient webTestClient;
@MockBean
SampleService mockSampleService;
@Test
public void hello() throws Exception {
Mockito.when(mockSampleService.getName()).thenReturn("younghwan");
webTestClient.get().uri("/hello").exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("hello younghwan");
}
}
| 슬라이스 테스트 어노테이션
SpringBootTest는 수많은 빈들을 등록하여 테스트에 필요한 의존성을 추가해 준다. 그래서 이 많은 빈들을 등록하지 않고 필요한 빈들만을 등록하여 테스트하고자 한다면 슬라이스 테스트 어노테이션을 통해 진행할 수 있다.
아래 @WebMvcTest 어노테이션을 등록하게 되면 웹 테스트를 하는데 필요한 @Controller, @ControllerAdvice, @JsonComponent 등의 어노테이션만 등록하게 된다. 이 밖에 테스트를 하는데 필요하지 않은 어노테이션은 등록되지 않기 때문에 웹 테스트말고 다른 테스트를 하고자할 경우에는 직접 의존성을 추가해야되는 번거로움이 있다.
package me.kyhslam.springdemo.sample;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@RunWith(SpringRunner.class)
@WebMvcTest(SampleController.class)
public class SampleControllerTest {
@MockBean
SampleService mockSampleService;
@Autowired
MockMvc mockMvc;
@Test
public void hello() throws Exception {
Mockito.when(mockSampleService.getName()).thenReturn("younghwan");
mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
.andExpect(MockMvcResultMatchers.content().string("hello younghwan"));
}
}
| OutputCapture 사용한 테스트
스프링부트에서는 OutputCapture를 통해 콘솔에 출력되는 모든 것을 캡쳐하여 테스트하는 방법도 제공한다.
package me.kyhslam.springdemo.sample;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleController {
Logger logger = LoggerFactory.getLogger(SampleController.class);
@Autowired
private SampleService sampleService;
@GetMapping("/hello")
public String hello(){
logger.info("younghwan");
System.out.println("skip");
return "hello " + sampleService.getName();
}
}
package me.kyhslam.springdemo.sample;
import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@RunWith(SpringRunner.class)
@WebMvcTest(SampleController.class)
public class SampleControllerTest {
@Rule
public OutputCapture outputCapture = new OutputCapture();
@MockBean
SampleService mockSampleService;
@Autowired
MockMvc mockMvc;
@Test
public void hello() throws Exception {
Mockito.when(mockSampleService.getName()).thenReturn("younghwan");
mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
.andExpect(MockMvcResultMatchers.content().string("hello younghwan"));
Assertions.assertThat(outputCapture.toString())
.contains("younghwan")
.contains("skip");
}
}
'📚 Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot #12] 스프링 웹 MVC - 정적 리소스 (0) | 2020.05.03 |
---|---|
[Spring Boot #11] 스프링 웹 MVC - HttpMessageConverters (0) | 2020.05.03 |
[Spring Boot #9] 스프링 부트 로깅(Logging) (0) | 2020.04.28 |
[Spring Boot #8] 스프링 부트 프로파일(Profile) (0) | 2020.04.28 |
[Spring Boot #7] 스프링 부트 외부 설정 (0) | 2020.04.27 |