인수 조건을 검증하는 테스트
실제 요청/응답하는 환경과 유사하게 테스트 환경을 구성하는 것이 중요
인수 테스트 도구
테스트 서버에 요청을 보내기 위한 라이브러리
MockMVC
@SpringBootTest를 사용할 필요가 없음
@WebMvcTest를 통해서 Presentation Layer Bean들만 불러옴 → 보통 Controller Layer의 유닛테스트를 진행하기 위해 사용
Controller 영역의 빈만 로딩하기 때문에 속도가 빠름
가독성면에서는 조금 딸림
@Test
public void getMember() throws Exception {
mockMvc.perform(get("/members/1")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id", Matchers.is(1)))
}
WebTestClient
RestAssured
@SpringBootTest의 webEnvironment 속성의 RANDOM_PORT를 활용
전구간 테스트에 사용
모든 빈을 로딩해야하기 때문에 속도가 느림
BDD 스타일로 작성할 수 있어 가독성이 좋음 (given/when/then)
@Test
public void getMember() {
given().
accept(MediaType.APPLICATION_JSON_VALUE).
when().
get("/members/1").
then().
log().all().
statusCode(HttpStatus.OK).
assertThat().body("id", equalTo(1));
}
테스트 데이터는 어떻게 만들까?
Repository를 활용해서 초기화
그래서 실제 API 요청을 통해서 데이터를 생성 → 덜 깨지기 위한 테스트를 만들 수 있음
대신 테스트를 하기 위한 사전 준비 과정에 노력이 많이 필요
Test Double
public interface MailService {
public void send (Message msg);
}
public class MailServiceStub implements MailService {
private List<Message> messages = new ArrayList<Message>();
public void send (Message msg) {
messages.add(msg);
}
public int numberSent() {
return messages.size();
}
}
진짜 대신에 가짜를 사용하는 것에 대해 통용해서 부르는 말
Stub
전체 중 일부라는 뜻인데, 모든 기능 대신에 일부 기능에 집중하여 임의로 구현한다는 뜻 → 일부 기능이라 함은 테스트를 하고자 하는 기능
테스트 입력에 집중을 하는가? 그 입력 값에 따라 리턴하는 결과 값을 비교하는가?
public void testOrderSendsMailIfUnfilled() {
Order order = new Order(TALISKER, 51);
MailServiceStub mailer = new MailServiceStub();
order.setMailer(mailer);
order.fill(warehouse);
assertEquals(1, mailer.numberSent());
}
Mock
스마트폰 가게에 가면 핸드폰 모형이 존재함 → 실제와 동일한 기능을 하지는 않지만 대략 이렇게 생겼고, 크기는 이렇다 등을 알려주는 용도
테스트에서는 호출시 동작이 잘 되었는지 화인하는데 쓰임
테스트 출력/결과에 집중하는가? 정상적으로 호출되었는지가 더 중요한가?
Order order = new Order(TALISKER, 51);
Mock warehouse = mock(Warehouse.class);
Mock mailer = mock(MailService.class);
order.setMailer((MailService) mailer.proxy());
mailer.expects(once()).method("send");
warehouse.expects(once()).method("hasInventory")
.withAnyArguments()
.will(returnValue(false));
order.fill((Warehouse) warehouse.proxy());
}
작업을 하다가 테스트 간에 서로 영향을 주는 부분이 있었음
truncate
시켜줌ATDD 완성 후 TDD