spring boot - @Test로 Controller API 호출 테스트하기 (통합테스트)

spring boot 통합 테스트

스프링 부트로 web 서버를 개발.
client 입장에서 url로 호출시 controller가 잘동작 하는지 테스트하려고 한다.

CodeBase

  • Spring Test
  • JUnit 4.x
  • Hamcrest
  • Mockito 1.x
  • JsonPath

SpringBootTest

통합테스트

  • @ContextConfiguration
  • 전체 환경이 다 로딩됨. 실제 애플리케이션 기동 시와 거의 유사

SpringBootTest

SpringBootTest.WebEnvironment

  • MOCK(default) : with MockMvc
  • RANDOM_PORT : with embedded WAS
  • DEFINED_PORT : with embedded WAS
  • NONE : none Web. 일반 Service 테스트 시 용이

실제 Port를 알고 싶다면 @LocalServerPort 를 이용해서 주입

@TestConfiguration

테스트 시에만 사용되는 구성
SpringBootConfiguration 때문에 다른 테스트에서 참조될 수 있으므로 주의 요망

Mocking

  • Mockito
  • @MockBean
  • @SpyBean

@MockBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RunWith(SpringRunner.class)
@SpringBootTest // !!!
public class MyTests {

@MockBean
private RemoteService remoteService;

@Autowired
private Reverser reverser;

@Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
}
}

@SpyBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RunWith(SpringRunner.class)
@SpringBootTest // !!!
public class MyTests {

@SpyBean
private RemoteService remoteService;

@Autowired
private Reverser reverser;

@Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
then(this.remoteService).should(times(1)).someCall();
}
}

@WebMvcTest (slice)

  • Spring MVC 환경이 통합된 상태이지만, 하나의 Controller를 테스트.
  • 실질적으로 통합테스트
  • @AutoConfigureMockMvc를 이용하므로 MockMvc를 사용할 수 있음
  • value 넣어서 필요한 class만 로딩

@DataJpaTest

  • Spring Data Jpa 환경이 통합된 상태로 Repository를 테스트할 수 있음.
  • 실제 DB를 연동하거나 내장된 DB(ex:H2)를 사용할 수도 있음
    • @AutoConfigureTestDatabase(replace=Replace.NONE)
  • 기본적으로 트랜젝션 처리도 가능하며 기본전략은 Rollback

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringRunner.class)
@DataJpaTest
public class ExampleRepositoryTests {
@Autowired
private UserRepository repository;

@Test
public void testExample() throws Exception {
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getVin()).isEqualTo("1234");
}
}

@RestClientTest

  • 통신할 서버를 mocking해서 restClient를 테스트 가능하게 함
  • jackson, GSON 지원

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RunWith(SpringRunner.class)
@RestClientTest(RemoteVehicleDetailsService.class)
public class ExampleRestClientTest {

@Autowired
private RemoteVehicleDetailsService service;

@Autowired
private MockRestServiceServer server;

@Test
public void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() throws Exception {
this.server.expect(requestTo("/greet/details"))
.andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}
}

Utils : EnvironmentTestUtils

EnvironmentTestUtils.addEnvironment(env, "org=Spring", "name=Boot");

Utils : TestRestTemplate

통합테스트용 (ex: @SpringBootTest)

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class RandomPortTestRestTemplateExampleTests {

@Autowired
private TestRestTemplate restTemplate;

@Test
public void exampleTest() {
String body = this.restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World");
}
}

Utils : WebTestClient <<개인적으로 추천

TestRestTemplate과 유사하나 fluent api를 지원

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class RandomPortWebTestClientExampleTests {

@Autowired
private WebTestClient webClient;

@Test
public void exampleTest() {
this.webClient.get().uri("/").exchange().expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}

출처

Test auto-configuration annotations

Comments