티스토리 뷰
시작은 일단 spring-boot-starter-test를 추가하는 것 부터
test scope으로 추가
@SpringBootTest
@SpringBootTest가 하는 역할은 @SpringBootApplication을 찾아서 테스트를 위한 빈들을 다 생성한다. 그리고 @MockBean으로 정의된 빈을 찾아서 교체한다.
@RunWith(SpringRunner.class)랑 같이 써야 함
빈 설정 파일은 안해주나? 알아서 찾는다. (@SpringBootApplication)
SpringBootTest.webEnvironment
MOCK : mock servlet environment. 내장 톰캣 구동 안함.
package io.namjune.springbootconceptandutilization.sample;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
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;
(SpringRunner.class)
(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class SampleControllerTest {
MockMvc mockMvc;
public void hello() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("hello namjune"))
.andDo(print());
}
}
RANDOM_PORT, DEFINED_PORT: 내장 톰캣 사용 함
RANDOM_PORT를 사용하면 실제 내장 톰캣을 사용한다. 이때는 MockMvc 대신 RestTemplate를 사용할 수 있다.
실제 가용한 포트로 내장톰캣을 띄우고 응답을 받아서 테스트를 수행한다.
package io.namjune.springbootconceptandutilization.sample;
import static org.assertj.core.api.Assertions.assertThat;
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.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
(SpringRunner.class)
(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
TestRestTemplate testRestTemplate;
public void hello() {
String result = testRestTemplate.getForObject("/hello", String.class);
assertThat(result).isEqualTo("hello namjune");
}
}spring5 webflux에서 추가된 RestClient중에 하나인 WebTestClient도 사용할 수 있다. 기존에 사용하던 WebClient는 synchronous하게 동작하기 때문에 요청 하나 보내고 그 요청이 끝나고 난 다음에 다음 요청을 보낼 수 있었지만, WebTestClient는 asynchronous하게 동작하므로 요청을 보내고 기다리지 않는다. 후에 응답이 오면, 콜백 이벤트를 실행할 수 있다. 따라서, Test코드에서도 WebClient와 비슷한 API를 사용할 수 있다.
webflux 의존성을 추가해야 한다.
API가 restTemplate보다 가독성이 좋다.(추천)
아래의 @MockBean 참고
implementation('org.springframework.boot:spring-boot-starter-webflux')
...package io.namjune.springbootconceptandutilization.sample;
import static org.mockito.Mockito.when;
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.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
(SpringRunner.class)
(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
WebTestClient webTestClient;
SampleService mockSampleService;
public void hello() {
when(mockSampleService.getName()).thenReturn("kim");
webTestClient.get().uri("/hello").exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("hello kim");
}
}
NONE: 서블릿 환경 제공 안 함.
@MockBean
위의 경우 테스트가 너무 크다. Controller 테스트코드에서 Service단까지 흘러간다. 컨트롤러만 테스트하고 싶을 경우 서비스 객체를 MockBean으로 만들어서 사용할 수 있다.
ApplicationContext에 들어있는 빈을 Mock으로 만든 객체로 교체함
모든 @Test 마다 자동으로 리셋. 직접 리셋을 관리 하지 않아도 된다.
package io.namjune.springbootconceptandutilization.sample;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
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.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
(SpringRunner.class)
(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
TestRestTemplate testRestTemplate;
SampleService mockSampleService;
public void hello() {
when(mockSampleService.getName()).thenReturn("kim");
String result = testRestTemplate.getForObject("/hello", String.class);
assertThat(result).isEqualTo("hello kim");
}
}
슬라이스 테스트
레이어 별로 잘라서 테스트 하고 싶을 때
@JsonTest
json 테스트를 하고싶을 경우 @SpringBootTest 대신 @JsonTest를 선언하고, JacksonTester를 주입받아서 사용하면 된다.
@WebMvcTest
컨트롤러만 따로 테스트 할 경우 사용한다. 웹과 관련된 클래스들만 빈으로 등록이 되고 일반적인 컴포넌트들은 빈으로 등록이 되지 않는다. 이렇게 의존성이 끊기기 때문에, 사용하는 다른 의존성 예를 들면 서비스와 같은 객체들은@MockBean을 사용해서 만들어 사용해야 한다.
@WebFluxTest
@DataJpaTest
...
6-2. 테스트 유틸
스프링 테스트가 제공하는 테스트 유틸리티가 4가지 있다.
OutputCapture
TestPropertyValues
TestRestTemplate
ConfigFileApplicationContextInitializer
Junit에 있는 Rule을 확장해서 만든 OutputCapture가 제일 많이 쓰인다.
OutputCapture는 로그를 비롯해서 콘솔에 찍히는 모든 것을 캡쳐한다.
로그 메세지가 어떻게 찍히는지 테스트할 수 있다.
@Rule을 선언하고,
Junit이 제공하는 OutputCapture를 public으로 만든다.(@Rule의 제약사항. 빈을 주입받는게 아님)
public class SampleController {
Logger logger = LoggerFactory.getLogger(SampleController.class);
private final SampleService sampleService;
("/hello")
public String hello() {
logger.info("hello logger");
System.out.println("hello sout");
return "hello " + sampleService.getName();
}
}
(SpringRunner.class)
(SampleController.class)
public class SampleControllerTest {
public OutputCapture outputCapture = new OutputCapture();
SampleService mockSampleService;
MockMvc mockMvc;
public void hello() throws Exception {
when(mockSampleService.getName()).thenReturn("kim");
mockMvc.perform(get("/hello"))
.andExpect(content().string("hello kim"));
assertThat(outputCapture.toString())
.contains("hello")
.contains("sout");
}
}
'ICT Eng > Spring' 카테고리의 다른 글
[Spring boot] HttpMessageConverters (0) | 2019.01.10 |
---|---|
[Spring Boot] 스프링 웹 MVC (0) | 2019.01.10 |
[Spring Boot] 스프링 부트 로깅(기본 로깅, 커스텀 로깅) (0) | 2018.12.10 |
[Spring Boot] 스프링 부트 외부설정 (0) | 2018.12.05 |
[Spring Boot] 스프링 부트의 의존성 관리, 자동 설정, 내장 웹 서버 (0) | 2018.11.15 |
- Total
- Today
- Yesterday
- Java
- ORM
- 젠킨스
- Wisoft
- Spring
- 순환
- AWS
- Recursion
- springboot
- Algorithm
- 알고리즘
- 레드블랙트리
- 라즈베리파이
- 정렬
- Vue.js
- IT융합인력양성사업단
- vuejs
- 한밭이글스
- 시간복잡도
- RBT
- 스프링부트
- Raspberry Pi
- vuex
- JPA
- 자바
- 인프런
- 무선통신소프트웨어연구실
- github
- Spring Boot
- 한밭대학교
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |