Blog Content

    티스토리 뷰

    [TEST] REST Assured를 사용한 REST API 테스트

    REST Assured Java 라이브러리를 사용하여 REST 어플리케이션의 HTTP Endpoint에 초첨을 맞춘,

    API 테스트 코드 작성 방법에 대해 학습해봅시다.


    Introduction



    Java 클래스의 동작을 확인하는 Unit 테스트의 수행은, 테스트 전략의 첫 단계일 뿐입니다.

    개별 Java클래스가 독립작으로 잘 작동한다고 해서

    모든 클래스가 함께 묶일 때 어플리케이션 자체가 올바르게 작동한다는 것을 의미하는 것은 아닙니다.


    기본 단위테스트 외에도 통합테스트(모듈에 초점을 맞춘 테스트),

    기능 테스트 (배포된대로 어플리케이션을 사용하는 end-to-end 테스트),

    사용자 승인 테스트 (GUI 테스트) 가 있습니다.


    이 포스팅에서는 자바 클래스로 직접 작동하지 않는 기능 테스트를 다룰 것입니다.


    오늘날의 대부분 어플리케이션은 JSON 데이터를 주고 받는 일종의 HTTP endpoint로 API를 노출합니다.

    이러한 Endpoint는 GUI 레이어 또는 다른 기술의 back-end application에서 사용할 수 있습니다.

    전체 개발 라이프 사이클을 적절하게 다루고, 테스팅 피라미드 패러다임을 올바르게 따르기를 원한다면

    이러한 HTTP Endpoint가 적절하게 잘 작동하는지 확인해야 합니다.


    학습 목표


    1. REST Assured - API 테스트용 Java 라이브러리 다운로드 및 설정

    2. HTTP Endpoint와의 상호 작용을 수행하는 간단한 테스트

    3. 클라이언트와 HTTP Endpoint 사이에 "conversation"이 필요한 보다 복잡한 기능 테스트

    4. Request, Response의 다양한 방법


    Rest Assured를 사용한 REST API 테스트는 Black box 테스트입니다.

    어플리케이션에 Request를 보내고, Response를 받고 미리 결정된 결과와 비교합니다.


    테스트 대상 어플리케이션이 어떤 언어로 작성이 되었는지는, REST Assured와는 관련이 없습니다.

    REST Assured는 테스트를 JSON 및 HTTP를 기반으로 합니다.

    REST Assured를 사용하여 Java 뿐만 아니라

    Python, Ruby, .Net 등으로 작성된 어플리케이션에 대한 테스트 코드를 작성할 수 있습니다.


    어플리케이션이 HTTP endpoint를 제공하는 한, REST Assured는 구현 프로그래밍 언어와 상관 없이 테스트할 수 있습니다만,

    구현과 단위테스트에 동일한 언어를 사용할 것이기 때문에

    JAVA 어플리케이션용 REST Assured를 사용하는 것이 편리할 것입니다.


    사전 조건

    • HTTP/REST/JSON API 가 있는 샘플 JAVA 프로젝트
    • 프로젝트를 빌드하는 유효한 pom.xml 파일
    • Maven 설치
    • Maven dependency를 다운로드하기 위한 인터넷 연결


    REST Assured는 JUnit에서 작동하므로, JUnit에 대한 어느정도의 지식은 갖추고 있어야 합니다. Hamcrest 지식은 도움이 되지만 우리는 Hamcrest matchers를 사용할 것이기 때문에 필수적으로 알아야 할 지식은 아닙니다.

    또한, Maven 빌드에 대한 방법을 이미 알고 있다고 가정하겠습니다.



    REST Assured 소개



    REST Assured는 REST 웹 서비스를 검증하기 위한 Java 라이브러리입니다.

    HTTP endpoint에 대한 연결 및 예상되는 결과를 설명하는 친숙한 DSL (Domain Specific Languages)을 제공합니다.


    간단한 예제를 살펴볼까요?


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import org.junit.Test;
    import io.restassured.RestAssured;
    public class SampleTest {
        @Test
        public void test() {
            RestAssured.given()
                        .when().get("http://www.google.com")
                        .then().statusCode(200);
        }
    }
     
    cs


    이 JUnit 테스트는 Google에 연결하고, GET 호출을 수행하며, HTTP 코드 200/success가 반환되는지 확인합니다.

    일반적인 JUnit assert 문이 없습니다.

    REST Assured는 반환된 status code에 따라 자동으로 pass 또는 fail을 판단합니다.


    REST Assured 설정


    pom.xml 에 다음과 같은 Dependency를 추가해주어야 합니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
        <dependencies>
            <dependency>
                <groupId>io.rest-assured</groupId>
                <artifactId>rest-assured</artifactId>
                <version>3.0.3</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.8.1</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    cs



    GSON은 API를 Request Body에 Json형식으로 호출할 때, 자동으로 Json 형식으로 호출하도록 해줍니다.



    REST Assured 특징

    given-when-them 패턴을 이용한 코드를 작성합니다.

    given : Test setup (테스트시 필요한 데이터, 및 파라미터를 셋팅합니다.)
    when : Test action (Method type을 정의해줍니다.)
    then : Test verification (Response Data를 검증합니다.)


    REST Assured 사용법

    Parameters

    1
    2
    3
    4
    5
    given().
           param("param1""value1").
           param("param2""value2").
    when().
           get("/something");
    cs

    REST Assured는 HTTP method에 기반하여 parameter type을 자동으로 결정합니다.
    GET type인 경우에는, query parameters로
    POST type인 경우에는 form parameters로 인식합니다.

    하지만, PUT, POST type에서 query parameter와 form parameter를 함께 사용할 때는 정확하게 명시해주어야 합니다.

    1
    2
    3
    4
    5
    given().
           formParam("formParamName""value1").
           queryParam("queryParamName""value2").
    when().
           post("/something");
    cs


    여러 값을 가지고 있는 parameter의 경우에는

    1
    given().param("myList""value1""value2"
    cs


    다음처럼 parameter명과 값들을 적어주거나 List에 담아 호출합니다.

    1
    2
    3
    4
    5
    List<String> values = new ArrayList<String>();
    values.add("value1");
    values.add("value2");
     
    given().param("myList", values)
    cs


    path parameter

    1
    post("/reserve/{hotelId}/{roomNumber}""My Hotel"23);
    cs


    Response JSON의 Assersion 정의

    방법 1 : then().assertThat() 을 이용하는 방법
    방법 2 : Response Message에서 Assert 구문을 이용하는 방법

    Response Data 검증

    1. equalTo : Response Body, Content가 원하는 값으로 return 되었는지 확인할 때
    ex : then().assertThat().body(equalTo("something"))

    2. hasItems : Response Body의 여러 값 중 특정한 값이 포함되어 있는지 확인할 때
    ex : then(). assertThat().body("lotto.winners.winnerId", hasItems(23, 54));

    3. startsWith , endsWithPath : Response Body의 특정 값의 시작하는 값, 끝나는 값을 확인할 때
    ex : then(). assertThat(). body("href", endsWithPath("userId"));
    ex : body("href", and(startsWith("http:/localhost:8080/"), endsWithPath("userId")));

    4. Response Time 측정
    ex : long timeInMs = get("/").time()
    ex : when(). get("/"). then(). time(lessThan(2000L)); // Milliseconds

    5. size : Response Body data의 size 검증
    ex : then().assertThat().body("size()", equalTo(10))

    6. containsString : Response Data 값에 특정 String이 포함되어 있는지 검증할 때
    ex : then().assertThat(). body(containsString("some"))


    Sample Java Application

    실습 사이트 : https://jsonplaceholder.typicode.com/ 

    이 사이트는 Rest API 테스트를 해볼 수 있는, Online Fake API를 제공하고 있습니다.

    참고 : HTTP 상태 코드


    이 사이트에서는 다음과 같은 Resources와 Routes가 있습니다.

    Resources

    Inspired by common use cases.

    /posts100 items
    /comments500 items
    /albums100 items
    /photos5000 items
    /todos200 items
    /users10 items

    Routes

    All HTTP verbs are supported.
    View usage examples.

    GET/posts
    GET/posts/1
    GET/posts/1/comments
    GET/comments?postId=1
    GET/posts?userId=1
    POST/posts
    PUT/posts/1
    PATCH/posts/1
    DELETE/posts/1


    그 중에 몇가지 함께 해봅시다.


    모든 Post를 조회하는 API

    Method : GET , API URL : /posts
    1
    2
    3
    4
    5
    6
    7
        @Test
        public void getPostsTest() {
            RestAssured.given()
                        .when().get("/posts")
                        .then().statusCode(200)
                                .log().all();
        }
    cs


    포스트를 등록하는 API 

    Method : POST, API URL : /posts
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
        @Test
        public void addPostTest() {
            Map<String, Object> requestData = new HashMap<>();
            requestData.put("title""foo");
            requestData.put("body""bar");
            requestData.put("userId"1);
            
            RestAssured.given()
                            .contentType("application/json")
                            .body(requestData).log().all()
                        .when()
                            .post("/posts")
                        .then()
                            .statusCode(201)
                            .assertThat().body("title", equalTo("foo"))
                            .assertThat().body("body", equalTo("bar"))
                            .assertThat().body("userId", equalTo(1))
                            .log().all();
        }
    cs


    포스트를 수정하는 API

    Method : PUT, API URL : /posts/{postId
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
        @Test
        public void updatePostTest() {
            Map<String, Object> requestData = new HashMap<>();
            requestData.put("id"1);
            requestData.put("title""fooupdate");
            requestData.put("body""bar update");
            requestData.put("userId"1);
            
            RestAssured.given()
                            .contentType("application/json")
                            .pathParam("postId"1)
                            .body(requestData)
                            .log().all()
                        .when()
                            .put("/posts/{postId}")
                        .then()
                            .statusCode(200)
                            .assertThat().body("id", equalTo(1))
                            .assertThat().body("title", equalTo("fooupdate"))
                            .assertThat().body("body", equalTo("bar update"))
                            .assertThat().body("userId", equalTo(1))
                            .log().all();
        }
    cs
    }


    포스트를 삭제하는 API

    Method : DELETE, API URL : /posts/{postId}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        @Test
        public void deletePostTest() {
            
            RestAssured.given()
                            .pathParam("postId"1)
                            .log().all()
                        .when()
                            .delete("/posts/{postId}")
                        .then()
                            .statusCode(200)
                            .log().all();
        }
    cs



    결론

    REST Assured Java 라이브러리를 사용하여 어플리케이션의 REST endpoint에 대한 단위테스트를 작성해보았습니다.

    1. Maven을 통한 REST Assured설정
    2. REST Assured테스트를 구성하는 방법
    3. HTTP Status code를 검사하는 기본 테스트코드 작성 방법
    4. Java Map을 사용하여 JSON 형식의 데이터를 전송하는 방법
    5. Hamcrest matchers를 사용하여 response data를 검증하는 방법

    우리는 간단하게 위의 5가지 항목을 함께 학습해보았습니다.
    이 외에도 REST Assured를 활용 방법은 다양하고 공식 REST Assured 사이트를 이용하면 더 많은 정보를 얻으실 수 있습니다.


    포스팅이 도움 되셨다면 공감 및 댓글 부탁드립니다 :)


    Comments