GraphQL e2e테스트 쉽게 하기 with Karate

햄햄·2023년 8월 11일
0

스프링부트 프로젝트에서 GraphQL API를 개발하며 e2e 테스트를 작성하는 데 매우 유용했던 방법을 소개한다.

Karate

e2e 테스팅 툴로는 Karate를 이용한다. Karate는 Gherkin 문법을 쓰는 테스팅 툴로, e2e 테스트를 심플하게 작성할 수 있다. 기본적인 설정만 해두면 e2e 테스트를 매우 빠르게 추가할 수 있으므로 스프링과 GraphQL을 쓴다면 꼭 사용해보기를 추천한다.

왜 Karate인가?

개인적으로 Karate를 GraphQLTester보다 선호하는 이유는 데이터 검증이 매우 간편하기 때문이다. jsonPath를 활용하기 때문에 depth가 깊은 데이터여도 특정 필드만 간편하게 테스트할 수 있다. 공식 문서를 보면 매우 다양한 assertion 샘플이 있는데, 유용한 몇개만 외워도 심플하면서도 강력한 assertion을 작성할 수 있다.

그리고 한 테스트 파일에서 다른 테스트 파일을 불러와 실행시킬 수 있기 때문에 API 테스트에 반복되는 설정 및 assertion은 템플릿 파일로 만들어 재사용할 수 있다는 점도 큰 장점이다.

테스트 환경 구성

테스트를 작성하기 전에 먼저 테스트 환경을 구성해보자. 프로젝트에 다음과 같이 설정을 추가해준다.

※기존 프로젝트 구성에 따라 설정 방법이 다를 수도 있다. 자세한 내용은 Karate 문서를 참조하자.

1. build.gradle

dependencies {
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2'
    testImplementation 'com.intuit.karate:karate-junit5:1.1.0'
}

test {
    systemProperty "karate.options", System.properties.getProperty("karate.options")
    systemProperty "karate.env", System.properties.getProperty("karate.env")
    outputs.upToDateWhen { false }
    testLogging.showStandardStreams = true
}

sourceSets {
    test {
        resources {
            srcDir file('src/test/java')
            exclude '**/*.java'
        }
    }
} 

2. .gitignore

target/

3. test 패키지 :classpathlogback-test.xml 추가

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
 
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
  
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>target/karate.log</file>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>    
   
    <logger name="com.intuit.karate" level="DEBUG"/>
   
    <root level="info">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>
  
</configuration>

4. 인텔리제이 커뮤니티 에디션일 경우 Cucumber for Java 플러그인 설치

GraphQL 테스트 작성

먼저 다른 테스트에서 재사용할 테스트 파일을 작성한다. 이 파일에선 모든 요청에 공통으로 들어갈 HTTP header를 설정한다. 그리고 테스트할 graphql 쿼리를 읽어온 후, post 요청을 보낸다. 응답에 errors 필드가 존재하면 테스트가 실패한다.
call_graphql_with_query.feature

Feature: GraphQL API

  Scenario:
    * configure headers = {'Accept': 'application/json', 'Content-Type': 'application/json'}
    * def query = read('this:' + queryName + '.graphql')
    Given url 'http://localhost:8080/graphql'
    And request { query: '#(query)', variables: '#(variables)' }
    When method post
    Then status 200
    Then match response.errors == '#notpresent'

그런 다음 테스트할 GraphQL 쿼리를 위 파일과 같은 패키지에 생성한다.
getUser.graphql

query getUser($id: ID!) {
	getUser(id: $id) {
    	profile {
        	name
            age
        }
        grade
    }
}

이제 해당 쿼리를 테스트하는 테스트를 작성한다.

Feature: Get User Scenario Test

  Background:
    * def variables =
    """
    {
      "id": 1,
    }
    """

  Scenario: getUser
    * def response = call read('call_graphql_with_query.feature') { queryName: 'getUser', variables: #(variables) }
    * print response
    * match result..profile contains deep [{ name: #string, age: #number }]

queryName에 실행시킬 grpahql 파일 이름을 입력한 후 assertion을 작성하면 된다. print response는 선택 사항인데, 개발 중간 응답 값을 바로 확인할 수 있어 유용했다.

애플리케이션을 실행시킨 후 테스트를 실행시키면 테스트 결과를 확인할 수 있다. 이제 e2e 테스트를 추가하려면 GraphQL 쿼리와 Karate 테스트 몇줄만 작성하면 된다.

JUnit으로 감싸기

여기까지만 해도 유용하게 쓸 수 있지만, 코드를 수정하고 테스트를 실행시키고 싶을 때마다 애플리케이션 재실행 -> 테스트 실행을 반복해야 하는 번거로움이 있다. karate를 위한 Junit 코드를 추가하면 이런 번거로움을 해소할 수 있다.

먼저 test.java 패키지에 karate-config.js 파일을 추가하여 환경변수에서 port 번호를 가져올 수 있도록 설정한다.

function fn() {
    const port = karate.properties['test.server.port'] ?? '8080';
    return {baseUrl: 'http://127.0.0.1:' + port};
}

call_graphql_with_query.feature파일의 url을 다음과 같이 수정하여 위에서 설정한 baseUrl을 사용할 수 있도록 한다.

Given url baseUrl + '/graphql'

그리고 다음과 같이 Junit 테스트 코드를 추가한다.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class KarateTest {

    @LocalServerPort
    int port;

    @BeforeEach
    void setUp() {
        System.setProperty("test.server.port", String.valueOf(port));
    }

    @Karate.Test
    Karate test() {
        return Karate.run("실행시킬 karate 파일의 path");
    }
}

이제 .feature파일 대신 이 테스트 코드를 실행시키면 Karate 테스트가 실행된다. 테스트 실행 전 random port를 생성하여 test.server.port에 할당함으로써 e2e테스트가 작동된다. 테스트를 위해 앱을 실행시킬 필요도 없고, 커맨드 라인 한줄로 간편하게 테스트할 수도 있다.

github 예시

설명이 부족하게 느껴진다면 Karate 문서를 참조하시면 좋습니다. 질문도 환영합니다.

profile
@Ktown4u 개발자

1개의 댓글

comment-user-thumbnail
2023년 8월 11일

즐겁게 읽었습니다. 유용한 정보 감사합니다.

답글 달기