16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

WireMockをローカル環境に導入する

Last updated at Posted at 2020-12-06

この記事はZOZOテクノロジーズ #4 Advent Calendar 2020 7日目の記事です。
昨日は @ahiru___ さんの「MetricKit 入門」でした。ぜひご覧ください!

はじめに

普段はGoでAPIやバッチの開発をしています。
Goでは実装コードに対してテストコードを記述してコードの品質を保障します。ところが外部APIなどを利用する場合は、テストコードだけで動作保証は少し心配ですよね。動作を保障するためには実際にAPIにリクエストして動作確認したいところです。しかしセキュリティやアカウント発行などの理由で気軽にリクエストできないことも多々あると思います。
この記事はモックフレームワークとしてWireMock を個人的に導入した件を紹介します。

環境

  • macOS Catalina 10.15.7
  • docker 20.10.0

なぜ WireMock

調べると素晴らしいモックフレームワークはいくつもありましたが、WireMockに決めた理由を下にあげました。

  1. リクエスト・レスポンスのスタブをJSONのみで設定できる
  2. レスポンスを外部ファイル化できる
  3. リクエストの検証がリッチにできそう
  4. スタブ設定はAPI経由でできる
  5. docker対応
  6. 個人的にとても使いやすかった!

モックをいれた構成イメージ

以下のようにローカル環境の構成にモックを入れた構成を目標にします。環境をあまり汚したくないので、docker-composeで設定します。
概要イメージ

起動

DockerHubで公開されているイメージを使います。

$ docker pull rodolpheche/wiremock

# 起動する
$ docker run -it --rm -p 8080:8080 rodolpheche/wiremock

http://localhost:8080/__admin にアクセスすると何も設定されていない状態です。

設定方法

大まかな流れは下のように行います。

  1. WireMock起動
  2. スタブ(リクエストとレスポンス)を作成
  3. 作ったスタブをmappingsディレクトリに配置する

スタブに関しては、ドキュメントページを参照してください。
例:/api/helloにGETリクエストでアクセスし、成功するスタブです。

request_user1.json
{
    "request": {
        "method": "GET",
        "url": "/user/1"
    },
    "response": {
        "status": 200,
        "jsonBody": {
            "status": "Success",
            "name": "xxxx",
            "email": "xxx@example.com"
        },
        "headers": {
            "Content-Type": "application/json"
        }
    }
}

WireMockを起動しつつ /home/wiremock以下の mappingsディレクトリにスタブ設定したJSONファイルを配置します。

└── wiremock
    └── home
        ├── __files
        └── mappings ←ここにいれる

レスポンスの外部ファイル化

レスポンスを外部ファイルとして保存できます。要するに永続化できるのでファイルをレポジトリなどで管理できます。
例:/api/helloにGETリクエストでアクセスし、404エラーとなるスタブです。

request_user10.json
{
    "request": {
        "method": "GET",
        "url": "/user/10"
    },
    "response": {
        "status": 404,
        "headers": {
            "Content-Type": "application/json"
        },
        "bodyFileName": "path/to/response_404.json"
    }
}

以下が外部ファイルとしてリクエストと別で設定できます。編集に苦労しそうな複雑なレスポンスや長いレスポンスなどが必要な場合は便利です。

response_404.json
{
    "status": 404,
    "message": "record not found"
}

外部ファイルは__filesディレクトリに保存します。

└── wiremock
    └── home
        ├── __files ←このディレクトリに配置する
        └── mappings 

リクエストの検証

WireMockには Request Matching という機能があり、リクエストの動作検証に役に立ちます。

  • URL
  • HTTPメソッド
  • クエリパラメータ
  • ヘッダ
  • ベーシック認証
  • クッキー
  • リクエストボディ
  • Multipart/form-data

この機能がJSONのみで設定できてしまうのはとても素晴らしい!テストシナリオなど組み立てるときに役に立ちそうです。

検証例

ヘッダのトークンを限定しているリクエスト

// ヘッダの`authorization`の値が「token xxxxxxxxxxxxx」のリクエストを期待している設定
{
    "request": {
        "method": "GET",
        "headers": {
            "authorization": {
                "equalTo": "token xxxxxxxxxxxxx",
                "caseInsensitive": true
            }
        },
        "url": "/api/users?from=2020-12-25"
    },
    "response": {
        "status": 200,
        "headers": {
            "Content-Type": "application/json"
        },
        "bodyFileName": "2020-12-25.json"
    }
}

リクエストボディ


// 正規表現が使える
{
  "request": {
    "bodyPatterns": "/api/([a-z]*)\\?query=all"
    ...
  },
  ...
}

ドキュメントには多くの良いサンプルがあります。そちらを確認するのをおすすめします。

API経由でスタブ設定する

実はスタブはWireMockが用意しているAPIから登録ができます。( 参照: Admin API )

操作 URL メソッド
一覧 http://[WireMockのホスト]:[ポート]/__admin/mappings GET
登録 http://[WireMockのホスト]:[ポート]/__admin/mappings POST
保存 http://[WireMockのホスト]:[ポート]/__admin/mappings/save POST
削除 http://[WireMockのホスト]:[ポート]/__admin/mappings DELETE

WireMockの API は上に示した以外にも様々に用意されています。
ドキュメント:WireMock admin API

登録

Terminalなどでコマンド経由して登録もできますが、Postmanなどで登録するのが簡単だと思います。
作ったスタブはhttp://localhost:8080/__admin/mappings経由でモックサーバに登録できます。
Postmanでの登録画面

登録の自動化

APIで設定ができるということは、スクリプトなどを用意すれば登録など自動化できそうです。
load-stubs.png

スクリプト化する

スクリプトで設定ファイルの読み込み、各ファイルに対して登録APIを実行します。
今回はシェルスクリプトで以下のように実装しました。

setup_mock.sh
# WireMockサーバがlocalhost:8080で動作している場合
WIREMOCK_URL="http://localhost:8080/__admin/mappings"

# スタブJSONのフォルダをスキャンして、全JSONファイルに対して登録APIを実行する
for jsonfile in mocks/*.json ; 
do
    payload=$(jq 'walk(if type == "object" then with_entries(select(.key[0:1] != "#")) else . end)' $jsonfile)
    curl -X POST -d"$payload" $WIREMOCK_URL
done;

登録の実行例

実行すると下のようなレスポンスを受け取ります。スタブが正常に登録されるとUUIDが発行されます。

$ wiremock ./setup_mock.sh #スクリプト実行

{ "request": { "method": "GET", "url": "/user/1" }, "response": { "status": 200, "jsonBody": { "status": "Success", "name": "xxxx", "email": "xxx@example.com" }, "headers": { "Content-Type": "application/json" } } }
{
  "id" : "7c9a95b2-132d-49be-8ae8-06dad2cae500",
  "request" : {
    "url" : "/user/1",
    "method" : "GET"
  },
  "response" : {
    "status" : 200,
    "jsonBody" : {
      "status" : "Success",
      "name" : "xxxx",
      "email" : "xxx@example.com"
    },
    "headers" : {
      "Content-Type" : "application/json"
    }
  },
  "uuid" : "7c9a95b2-132d-49be-8ae8-06dad2cae500"
}%  

スタブの保存する

登録したスタブを保存するには上のスクリプト実行後に保存APIを実行する

# WireMockサーバがlocalhost:8080で動作している場合
WIREMOCK_SAVE_URL="http://localhost:8080/__admin/mappings/save"

# 登録しているスタブが永続化されます
curl -X POST $WIREMOCK_SAVE_URL

スクリプト実行するとmappingsPath+[発行されたUUID].json というファイルで保存されます。

└── wiremock
    └── home
        ├── __files
        └── mappings ←このディレクトリに保存される
          └── user1-849c36d2-c592-42f4-8c01-c4f81b8ec849.json

JSONファイルの内容は、スタブ設定しているものと同じです。そしてWireMockはファイルをID管理しているのがわかります。

user1-849c36d2-c592-42f4-8c01-c4f81b8ec849.json
{
  "id" : "849c36d2-c592-42f4-8c01-c4f81b8ec849",
  "request" : {
    "url" : "/user/1",
    "method" : "GET"
  },
  "response" : {
    "status" : 200,
    "jsonBody" : {
      "status" : "Success",
      "name" : "xxxx",
      "email" : "xxx@example.com"
    },
    "headers" : {
      "Content-Type" : "application/json"
    }
  },
  "uuid" : "849c36d2-c592-42f4-8c01-c4f81b8ec849",
  "persistent" : true,
  "insertionIndex" : 0
}

docker-compose設定

実際の環境では下のように開発するアプリとmockを組み込んで開発しています。

docker-compose.yml
version: "3"
services:
  app:
    build:
      context: .
      dockerfile: "docker/Dockerfile"
    volumes:
      - .:/github.com/xxxxx/mkn-wiremock
    ports:
      - 8888:8888
    tty: true
    networks:
      - mynetwork
  mock:
    image: wiremock/wiremock:latest-alpine
    volumes:
      - ".data/wiremock/stubs:/home/wiremock"
    ports:
      - 8080:8080
    networks:
      - mynetwork
    restart: on-failure
networks:
  mynetwork:

ポイント

WireMockはスタブを配置するディレクトリを/home/wiremockを期待しているので設定をします。
上の場合、ローカル環境の.data/wiremock/stubsディレクトリをそれにあてています。

その他のフレームワーク

調べたモックフレームワークです。

候補 概要
Mockapi.io Webベース。簡単にモックのエンドポイントが作れる。
mockify Go製。リクエストとレスポンスを簡単に設定できるライブラリ. RESTに対応。
Mocky Scalaベース。APIリクエストとレスポンスをモッキングできるツール
Karate TestフレームワークでAPIモックもできる。RESTだけではなくGraphQL、gRPCなども対応している

まとめ

この記事ではモックフレームワークのWireMockの機能の一部と自動化などを紹介しましたが、紹介しきれなかった機能もまだまだあります。WireMockとNewmanなどと組み合わせてテストシナリオの自動化なども実現できそうです。API開発やモックサーバを検討している方々の参考になれば幸いです。テストの世界は奥が深い。

参考サイト

16
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?