스프링부트 테스트
준비물
-
spring-boot-starter-test 의존성
- junit (unit test framework)
- jsonpath (json assertion)
- mockito (mocking framework)
- selenium (web scrapping)
-
junit test runner를 설정하는 @RunWith(SpringRunner.class)
-
스프링부트 테스트 어노테이션 @SpringBootTest / @JsonTest / @WebMvcTest
- @SpringBootTest의 기본 웹 환경은
WebEnvironment = SpringBootTest.WebEnvironment.MOCK
- 테스트할 때, 원래의 서블릿 컨테이너 대신
mocking container
를 띄운다. - 원래 서블릿처럼 DispatcherServlet과의 인터렉션이 가능
- 이를 위해
mockmvc
라는 클라이언트를 필수적으로 사용
- @SpringBootTest의 기본 웹 환경은
1
2
3
4
5
|
@RunWith(SpringRunner.class)
@SpringBootTest(WebEnvironment = Webenvironment.MOCK)
public class SampleControllerTest {
}
|
cs |
테스트 웹환경 MOCK
- @SpringBootTest(WebEnvironment = SpringBootTest.WebEnvironment.MOCK)
MockMvc
- test controller에
@AutoConfigureMockMvc
추가 @Autowired
로 MockMvc 주입받기- MockMvcRequestBuilders와 MockMvcRsultMatchers 패키지의 메소드를 이용하여 테스트
- get() : org.springframework.test.web.servlet.request.MockMvcRequestBuilders 패키지
- status() / content() / print() : org.springframework.test.web.servlet.result.MockMvcResultMatchers 패키지
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@SpringBootTest(WebEnvironment = Webenvironment.MOCK)
public class SampleControllerTest {
@Autowired
Mockmvc mockMvc;
@Test
public String hello(){
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("hello world"))
.andDo(print());
}
}
|
cs |
테스트 웹환경 RANDOM_PORT
- @SpringBootTest(WebEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
- MOCK과 달리, 실제 서블릿 컨테이너(ex. 내장 톰캣)가 랜덤 포트 위에서 동작
TestRestTemplate 이용
- RestTemplate?
- REST 서비스의 EndPoint를 호출할 수 있는 클라이언트 객체
- Spring 3부터 지원
- REST API 호출 이후 응답을 받을 때까지 기다리는
synchronous
client - getForObject(URL, 반환타입) : HTTP GET 요청의 결과를 객체로 반환
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@RunWith(SpringRunner.class)
@SpringBootTest(WebEnvironment = Webenvironment.RANDOM_PORT)
public class SampleControllerTest {
@Autowired
TestRestTemplaet testRestTemplate;
@Test
public String hello(){
String result = testRestTemplate.getForObject("/hello", String.class);
assertThat(result).isEqualTo("hello world");
}
}
|
cs |
WebTestClient 이용
spring-boot-starter-webflux
의존성 필요- WebTestClient?
- Spring 5부터 지원
- NonBlock + Async Web Client
- 비동기를 지원하므로 실제 웹 클라이언트와 동일하게 API 사용가능
- 편리함 : WebTestClient > MockMvc > TestRestTemplate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@RunWith(SpringRunner.class)
@SpringBootTest(WebEnvironment = Webenvironment.RANDOM_PORT)
public class SampleControllerTest {
@Autowired
WebTestClient webTestClient;
@Test
public String hello(){
webTestClient.get().uri("/hello").exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("hello world");
}
}
|
cs |
테스트 규모 제한하기
- Controller가 Service를 주입받아, URL Get Mapping에서 서비스의 메소드를 실행한 결과값을 반환하는 상황
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Service
public class SampleService {
public String getName() {
return "world";
}
}
@RestController
public class SampleController {
private SampleService sampleService;
SampleController(SampleService sampleService){
this.sampleService = sampleService;
}
@GetMapping("/hello")
public String hello(){
return "hello " + sampleService.getName();
}
}
|
cs |
- 컨트롤러만 테스트하고 싶은데, 주입받는 서비스 객체가 너무 크다면?
@MockBean
- Application Context 안의 SampleService Bean을 MockBean으로 교체
- 테스트 환경에서 해당 컨트롤러는 MockService를 사용
when()
과thenReturn()
으로 MockBean의 메소드 반환값을 변경할 수 있음- @Test마다 리셋되므로, 테스트 메소드 내에서 반환값 변경 등에 대한 리셋을 신경쓸 필요 없음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@RunWith(SpringRunner.class)
@SpringBootTest(WebEnvironment = Webenvironment.RANDOM_PORT)
public class SampleControllerTest {
@Autowired
WebTestClient webTestClient;
@MockBean
SampleService sampleService;
@Test
public String hello(){
when(mockSampleService.getName()).thenReturn("kkambi");
webTestClient.get().uri("/hello").exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("hello kkambi");
}
}
|
cs |
거대한 @SpringBootTest
- 큰 규모의 통합 테스트
- @SpringBootApplication을 찾아, 하위 패키지의 모든 빈을 스캔하고, 테스트용 Application Context에 등록
- @MockBean이 있다면 그들만 교체
Slice Test
@SpringBootTest를 대체
-
@JsonTest
- 우리의 Model이 Json형태로 나갈 때
JacksonTester<ExampleObject>
를 주입받음- 미리 만들어놓은 json와 비교하거나, json의 내용을 비교
-
@WebMvcTest(SampleController.class)
- 컨트롤러 하나만 테스트하고 싶을 때
- Web과 관련된 Bean만 등록
- @Controller, @ControllerAdvice, @JsonComponent, @Converter
- @Service와 같은 일반적인 @Component는 등록되지 않음
- Web Layer 아래 의존성이 모두 제거됨 -> 필요 의존성은 @MockBean으로 채워야 함
SampleService를 채운 것처럼!!
MockMvc
사용해야 함
테스트 유틸리티
스프링부트가 제공하는 테스트 유틸리티
- OutputCapture
- 스프링부트 2.2.0부터 deprecated되었으므로
OutputCaptureRule
을 이용 - junit의 @Rule을 확장하여 만듬
- 필수 : public으로 인스턴스를 생성해야 함
- 특징 : 로그를 비롯해, 콘솔에 찍히는 모든걸 캡쳐
- @Rule : junit에서 유연한 테스팅을 위해 제공하는 추가기능 같은 것들
- 스프링부트 2.2.0부터 deprecated되었으므로
- TestRestTemplate
- TestPropertyValues
- ConfigFileApplicationContextInitializer
'학습 > Spring' 카테고리의 다른 글
[spring] 스프링부트를 통한 스프링 웹 MVC 구축의 편리함 (0) | 2020.04.19 |
---|---|
[spring] 스프링부트의 Spring-Boot-Devtools (0) | 2020.04.18 |
[spring] 스프링부트의 로깅 (0) | 2020.04.16 |
[spring] 스프링의 @Configuration과 @Profile (0) | 2020.04.15 |
[spring] 스프링부트의 외부 설정 (활용) (0) | 2020.04.12 |
댓글