> Hello World !!!

     

@syaku

HTTP 클라이언트 테스트를 위한 WireMock - Test MockServer

클라언트에서 서버로 요청하는 프로그램을 개발하고 테스트를 하기 위해 대상 서버가 필요하다.

테스트 과정에서 서버에서 일어나는 일은 관심이 없다. 응답 후 테스트가 주요 목적일 것이다.

그래서 실제 서버로 테스트하지 않고 모의 서버를 이용하여 테스트하면 된다.

모의 서버를 구성하고 테스트하는 방법에 대해 가이드하였다.

테스트를 위한 모의 서버를 제공하는 라이브러리는 WireMock 과 MockServer 두가지가 있는 데 WireMock 을 사용하여 예제를 작성하였다. 그리고 Spring cloud 의존성을 사용하면 wiremock 이 포함되어 있으니 참고한다.

설치

standalone 버전이 있는 데 이건 WireMock 를 독립적으로 실행하여 Mock Server 를 운영할 수 있는 버전으로 보여진다. 그래서 일반 버전을 사용한다.

testCompile "com.github.tomakehurst:wiremock-jre8:2.31.0"

나는 Spring cloud 를 사용하므로 아래와 같이 설정했다.

ext.springCloudVersion = "Hoxton.SR11"

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

testImplementation "org.springframework.cloud:spring-cloud-starter-contract-stub-runner"

WireMock 포트 설정

@AutoConfigureWireMock(port = 0)

AutoConfigureWireMock 선언으로 스프링 설정을 자동 구성할 수 있다.

WireMock서버용 포트를 직접 설정할 수 있지만 랜덤 포트 사용을 권장하고 있다.

하지만 랜덤 포트를 사용하면 실제 서버의 포트와 다를 수 있어 properties를 재설정 해야한다.

아래와 같은 방법으로 해결할 수 있다.

@AutoConfigureWireMock(port = 0)
@TestPropertySource(properties = {
    "app.gateway-uri=http://localhost:${wiremock.server.port}"
})

반복되는 설정 코드를 줄이기 위해 아래와 같이 선언방식으로 사용하면 된다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigureWireMock(port = 0)
@TestPropertySource(properties = {
    "app.gateway-uri=http://localhost:${wiremock.server.port}"
})
public @interface WireMockTest {

}

WireMock은 요청과 응답을 stub이란 템플릿 파을을 구성하여 사용할 수 있다.

stub은 json 구조의 문법을 사용하며 동적인 부분은 handlebars.java 템플릿 엔진의 문법을 사용할 수 있다.

stub 파일의 기본 경로는 classpath:/mappings 이며 AutoConfigureWireMock 선언에서 경로를 변경할 수 있다. stub 경로의 하위 모든 json 파일을 읽는다.

sample-stub.json

{
  "mappings": [
    {
      "request": {
        "method": "GET",
        "urlPathPattern": "/account/v1/users/duplicate-username",
        "queryParameters": {
          "username": {
            "matches": ".*"
          }
        }
      },
      "response": {
        "headers" : {
          "Content-Type" : "text/plain"
        },
        "status": 200,
        "body": "true"
      }
    }
  ]
}

matches와 같은 속성은 요청 값에 대한 유효성 검증을 할 수 있다. 그외에 다양한 속성을 제공하니 가이드를 참고한다. 참고 - http://wiremock.org/docs/request-matching/

유효성 검증은 필수가 아니다. 필요할거나 요청을 명확하게 하려면 유효성 검증을 설정하는 것이 좋다.

테스트 코드에서 GET /account/v1/users/duplicate-username?username=test 요청하면 응답와 같은 응답을 받을 수 있다.

HTTP/1.1 200 OK
Content-Type: text/plain

true

matches 속성에 의해 username 파라메터에 값이 없으면 오류가 발생한다.

response body 가 문자열인 경우이며 json 인 경우는 jsonBody 속성을 사용해야 한다.

그외에도 다양한 속성이 있으니 가이드를 참고한다.

참고 - http://wiremock.org/docs/response-templating/

stub 의 스크립트적인 문법은 Handlebars.java 템플릿 엔진을 기반이라 동적인 문법도 사용이 가능하다.

사용하려면 응답에 아래와 같이 추가해야 한다.

"transformers": ["response-template"],

예를 들어 request 데이터를 response 에서 사용할 수 있다.

{
  "request": {
    "method": "POST",
    "url": "/account/v1/managers"
  },
  "response": {
    "headers" : {
      "Content-Type" : "application/json"
    },
        "transformers": ["response-template"],
    "status": 201,
    "jsonBody": {
      "id" : 1,
      "username" : "{{jsonPath request.body '$.username'}}",
      "name" : "{{jsonPath request.body '$.name'}}",
      "registeredOn" : "{{#assign 'dateTimeFormat'}}yyyy-MM-dd'T'HH:mm:ss.SSSSSS{{/assign}}{{now format=dateTimeFormat}}",
      "updatedOn" : null
    }
  }
}

참고

'Tech' 카테고리의 다른 글

OAuth 2.0 Simplified  (0) 2021.10.18
자주 사용하는 Git CLI (Command line interface)  (0) 2021.10.15
OpenFegin Example  (0) 2021.10.07
Java Database Connection TLS 보안 이슈  (0) 2021.10.07