Search
Duplicate

인수 테스트 도구

목차

Previous

인수테스트를 하기전 인수테스트는 무엇이고 어떤식으로 실습을하고 테스트를 진행하며 알아야할 기본적인 지식에 대해 학습하고 간단한 테스트를 만들어 실습해가며 학습한다.

테스트 환경 구축

인수테스트는 블랙박스 테스트의 성격(1)을 가지는게 좋다고 한다. 그렇기에 시스템 내부 코드를 직접 호출하는 것이 아닌 외부에서 요청하는 방식으로 검증하도록 한다.

인수 테스트 클래스 작성

테스트용 서버를 로드하도록 설정한다.
@SpringBootTest(2) 어노테이션을 클래스에 붙혀서 테스트를 위한 웹 서버를 사용한다.
webEnvironment(3)설정을 통해 웹 서버의 환경을 지정해줄 수 있다.
@DisplayName("지하철 역 관련 기능") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class StationAcceptanceTest { ... }
Java
복사

인수 테스트 객체 설정

테스트를 위한 서버에 API요청을 보내기 위해 클라이언트 객체를 설정해야 한다. 테스트를 위한 클라이언트 객체는 MockMvc, RestAssured, WebTestClient가 있으며, 현재 진행하는 ATDD과정에서는 RestAssured를 사용하기에 나도 RestAssured를 사용하도록 한다.
@DisplayName("지하철 역 관련 기능") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class StationAcceptanceTest { @LocalServerPort int port; @BeforeEach public void setUp() { RestAssured.port = port; } ... }
Java
복사

테스트 서버에 요청하는 로직 작성해보기

@DisplayName("지하철역을 생성한다.") @Test void createStation() { // given Map<String, String> params = new HashMap<>(); params.put("name", "강남역"); // when ExtractableResponse<Response> response = RestAssured.given().log().all() .body(params) .contentType(MediaType.APPLICATION_JSON_VALUE) .when() .post("/stations") .then().log().all() .extract(); ... }
Java
복사

테스트 응답 결과 검증하기

응답결과를 검증하는 방법으로는 RestAssured를 이용해 요청과 동시에 검증하는 방식과 AssertJ를 이용하는 방식이 있다.
1.
RestAssured를 이용한 방법
@DisplayName("지하철역을 생성한다.") @Test void createStation() { ... RestAssured.given().log().all() .body(params) .contentType(MediaType.APPLICATION_JSON_VALUE) .when() .post("/stations") .then().log().all() .statusCode(HttpStatus.CREATED.value()) .header("Location", notNullValue()); }
Java
복사
2. AssertJ 사용
import static org.assertj.core.api.Assertions.assertThat; ... @DisplayName("지하철역을 생성한다.") @Test void createStation() { ... ExtractableResponse<Response> response = RestAssured.given().log().all() .body(params) .contentType(MediaType.APPLICATION_JSON_VALUE) .when() .post("/stations") .then().log().all() .extract(); // then assertThat(response.statusCode()).isEqualTo(HttpStatus.CREATED.value()); assertThat(response.header("Location")).isNotBlank(); }
Java
복사

인수 조건 기반의 인수 테스트 만들기

인수 조건을 작성하기

Feature: 간략한 기능 서술 Background: 각 시나리오 사전 조건 Scenario: 시나리오(예시) 제목 Given: 사전조건 When: 발생해야하는 이벤트 Then: 사후조건 And: 앞선 내용에 추가적인 내용 기술
GraphQL
복사
인수조건 양식
해당과정의 1단계는 지하철 노선,역,구간 관리이기에 이에 해당하는 조건 예시를 만들어본다.
Feature: 지하철 역 관리 기능 Scenario: 지하철 역을 생성한다. When 지하철 역을 생성 요청한다. Then 지하철역이 생성된다. Scenario: 지하철 역을 삭제한다. Given 지하철 역이 등록되어있다. When 지하철 역을 삭제 요청한다. Then 지하철 역이 삭제된다.
GraphQL
복사

인수 테스트 작성시 팁

이제 작성한 인수 조건을 가지고 테스트케이스를 만들어야 생성및 구현해야하는데, 인수 테스트 클래스는 Feature를 기준으로 테스트 클래스를 나눌 수 있습니다.
Feature: 지하철 역 관리 기능 ... Feature: 지하철 노선 관리 기능 ... Feature: 지하철 구간 관리 기능
GraphQL
복사
위와 같이 세 가지 인수조건을 작성했을 경우 인수 테스트 클래스는
StationAcceptanceTest, LineAcceptanceTest, SectionAcceptanceTest 세개를 만들 수 있습니다.
그리고 이 클래스 안에 각각의 Feature아래있던 Scenario 를 기준으로 인수 테스트 메서드를 작성할 수 있습니다.
class StationAcceptanceTest { ... @DisplayName("지하철 역을 생성한다.") @Test void createStation(){ //test logic } @DisplayName("지하철 역을 삭제한다.") @Test void deleteStation(){ //test logic } ... }
Java
복사
이 때, 하나의 Feature 내부에 있는 Scenario는 같은 테스트 픽스쳐를 공유하는것을 추천합니다.

간단한 성공 케이스 우선 작성

테스트 케이스를 생성할때 처음부터 너무 복잡한 케이스를 작성하기보다는 동작가능한 간단한 성공 케이스로 시작하는게 좋습니다.
테스트가 실제로 동작하면서 실제 구조에 대해 더 나은 생각을 할 수도 있고, 이러한 과정에서 발생 가능한 실패를 처리하는 것과 성공 케이스 사이에서 우선순위를 가늠에 작성하는게 좋습니다.

Given / When / Then

테스트 로직을 작성할 때는 언제(When) 어떻게(Then)될지 검증하기 위해 데이터를 준비(Given)하는게 자연스럽습니다.
@DisplayName("지하철 역을 생성한다.") @Test void createStation(){ //given //지하철 역 파라미터 생성 Map<String, String> params = new HashMap<String, String>(){{ put("name", "강남역"); }}; //when ExtractableResponse<Response> response = 지하철_노선_생성_요청(params); //then 지하철_노선_생성됨(response); }
Java
복사

번외. JsonPath

JSON 객체의 요소를 쿼리하는 표준 방법.
경로 표현식을 사용하여 JSON문서에서 요소, 혹은 중첩된 요소나 배열을 탐색한다.

문법

JSONpath에서는 아래와같은 문법을 이용해 요소를 탐색할 수 있다.
예를들어, 아래와같은 JSON 데이터에서 city라는 key의 value를 얻어오고자 한다면 위의 나와있는 문법을 참고하면 $.address.city가 된다 한번 테스트 사이트에가서 테스트를 해보자.
{ "customerName":"John Doe", "address": { "streetAddress": { "number":"123", "street":"AnyStreet" }, "city":"Anytown" }, "orders": [ { "orderId":"23284", "itemName":"Widget", "itemPrice":"33.99" }, { "orderId":"63122", "itemName":"Gadget", "itemPrice":"22.50" }, { "orderId":"77284", "itemName":"Sprocket", "itemPrice":"12.00" } ] }
JSON
복사
Anytown이 정상적으로 나오는것을 확인할 수 있다.
실습및 학습이 더 필요하다면 아래 링크를 가서 연습하도록 하자.
(1). 소프트웨어의 내부 구조나 작동 원리를 모르는 상태에서 동작을 검증하는 방식.
(2). @SpringBootTest 어노테이션은 테스트에 사용 할 ApplicationContext를 쉽게 지정하도록 도와준다. 기존 @ContextConfiguration의 발전된 기능으로 SpringApplication에서 사용하는 ApplicationContext를 생성해서 작동한다.
(3). 해당 속성으로 테스트 서버의 실행 방법을 설정한다. (link)
MOCK: Mocking된 웹 환경을 제공하며 MockMvc를 사용한 테스트를 할 수 있다.
RANDOM_PORT: 실제 웹 환경을 구성
DEFINED_PORT: 실제 웹 환경을 구성하며 지정한 포트를 listen한다.
NONE: 아무런 웹 환경을 구성하지 않는다.