Contents
- 1 なぜモックサーバーが必要か?
- 2 WireMockとは?
- 3 WireMockの使い方
- 4 WireMockのエラー・例外
- 4.1 java.lang.RuntimeException: java.net.BindException: Address already in use: bind
- 4.2 Request was not matched
- 4.3 MappingFileException: Unrecognized field "yyy" (class StubMappingCollection), not marked as ignorable
- 4.4 MappingFileException: Unexpected character (']' (code 93)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
- 4.5 HTTP ERROR 500 FileNotFoundException
- 4.6 レスポンスが文字化けする
- 5 WireMock以外のモックサーバーソフトウェアの比較
なぜモックサーバーが必要か?
Webアプリケーションを開発していて、APIのモックが必要となるシーンはよくあります。特にフロントエンドを開発しているときに、バックエンドのAPIがまだできていないということは普通にあります。
フロントエンド開発でモックサーバーを利用する大きいメリットを3つ挙げておきます。
1つ目は、APIに相当するモックサーバーを用意しておけば、フロントエンドは本番と同じソースコードで開発を進めることができます。モックサーバーがなければ、フロントエンドのソースコードに、ダミーデータ用のJSONを置いたり、ダミーデータを直接画面のコードの中に埋め込んだりすることになり、ソースコードが汚れてしまいます。
2つ目は、レスポンスに応じたイベントの発生や画面制御の確認が簡単になります。モックサーバーではレスポンスを自由に書き換えられるため、欲しいデータのために外部キー制約をたどってテーブルのレコードを作っていく必要がなくなるからです。
3つ目は、動作確認する人(上長やレビュアー)も簡単に動かせるようになることです。動作確認する人もテーブルに画面を動かすためのデータを用意する必要がないため、簡単に動作確認できるようになります。
WireMockとは?
WireMockは実案件でも利用されています。とにかく使い方が簡単なのでお勧めです。
遅延レスポンスの実行や任意のレスポンスコードの発生など、正常系以外も簡単に実行できるため、API開発では必須ツールと考えています。
WireMockの3つの機能
- 柔軟性の高いデプロイ方法(スタンドアローン、Javaアプリに組み込む、JUnitで利用するなど)
- 強力なリクエストマッチング
- 記録・再生ができる
WireMockの使い方
WireMockを手に入れる
WireMock公式サイトから、スタンドアローン版WireMockのJARファイル(wiremock-standalone-2.27.2.jar)をダウンロードします。
ダウンロードしたwiremock-standalone-2.27.2.jarを、任意の場所に置きましょう。
APIやフロントエンドのプロジェクトとは違うディレクトリで別管理するのが良いでしょう。例えば、「プロジェクト名-mock」などが良いです。
WireMockを起動する
jar以外は何もない状態でまずはそのまま起動します。
D:\springhack\happy-library-mock>java -jar wiremock-standalone-2.27.2.jar -port 8082
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
/$$ /$$ /$$ /$$ /$$ /$$
| $$ /$ | $$|__/ | $$$ /$$$ | $$
| $$ /$$$| $$ /$$ /$$$$$$ /$$$$$$ | $$$$ /$$$$ /$$$$$$ /$$$$$$$| $$ /$$
| $$/$$ $$ $$| $$ /$$__ $$ /$$__ $$| $$ $$/$$ $$ /$$__ $$ /$$_____/| $$ /$$/
| $$$$_ $$$$| $$| $$ \__/| $$$$$$$$| $$ $$$| $$| $$ \ $$| $$ | $$$$$$/
| $$$/ \ $$$| $$| $$ | $$_____/| $$\ $ | $$| $$ | $$| $$ | $$_ $$
| $$/ \ $$| $$| $$ | $$$$$$$| $$ \/ | $$| $$$$$$/| $$$$$$$| $$ \ $$
|__/ \__/|__/|__/ \_______/|__/ |__/ \______/ \_______/|__/ \__/
port: 8082
enable-browser-proxying: false
disable-banner: false
no-request-journal: false
verbose: false
上のような表示が出たら、正常に起動できています。後はパスとレスポンスの設定を書けば良いだけです。
「java -jar wiremock-standalone-2.27.2.jar」で起動できますが、APIやフロントエンドが8080を使っている場合は、-portでポート番号を指定して起動します。
正常に起動できたら、次のディレクトリが生成されています。
- __files ・・・レスポンス用のJSONファイルを配置するディレクトリです。
- mappings・・・HTTPのパスやレスポンス内容やらを記述するディレクトリです。
WireMockのモックAPIの基本的な書き方
書き方1 mappingファイルにリクエストとレスポンスを書く
{
"request": {
"method": "GET",
"url": "/users"
},
"response": {
"status": 200,
"body": "Hello world!",
"headers": {
"Content-Type": "text/plain"
}
}
}
mappings配下にモックAPIの定義ファイルを配置します。
定義ファイルは.jsonで記述します。
ファイル名は.jsonであれば任意です。(urlと合わせる必要はありません。)
上記のように記述することで、このようなAPIになります。
1つのmappingファイルに複数のAPIを定義するには?
mappingファイルには"mappings"に配列で複数のAPIを定義することができます。
{
"mappings": [
{
"request": {
"method": "GET",
"url": "/users"
},
"response": {
"status": 200,
"body": "Hello world! /users",
"headers": {
"Content-Type": "text/plain"
}
}
},
{
"request": {
"method": "GET",
"url": "/users/profile"
},
"response": {
"status": 200,
"body": "Hello world! /users/profile",
"headers": {
"Content-Type": "text/plain"
}
}
}
]
}
mappingファイルをディレクトリで整理するには?
mappingディレクトリ配下に置かれた.jsonはすべてmappingファイルとして認識されるため、ディレクトリを作ることでURL構造に応じた整理ができます。
<root>
│ wiremock-standalone-2.27.2.jar
│
├─mappings
│ └─v1
│ ├─foo
│ │ bar.json
│ │ fugo.json
│ │
│ └─hoge
│ fuga.json
│
└─__files
上では3つの.jsonがありますが、どれも読み込まれます。
書き方2 mappingファイルにリクエストを、__files配下にレスポンスを置く
レスポンスをレスポンス用の.jsonファイルに外出しすることで、可読性が上がり、保守しやすくなるため、こちらの書き方を推奨します。
API定義の.jsonファイルの、responseのbodyFileName属性に__filesディレトリ配下のパスを記述するだけです。
{
"request": {
"method": "GET",
"url": "/foo"
},
"response": {
"status": 200,
"bodyFileName": "bar.json",
"headers": {
"Content-Type": "application/json"
}
}
}
{
"users": [
{
"id": "1000",
"name": "太郎"
},
{
"id": "2000",
"name": "次郎"
}
]
}
WireMockのエラー・例外
java.lang.RuntimeException: java.net.BindException: Address already in use: bind
> java -jar wiremock-standalone-2.27.2.jar
java.lang.RuntimeException: java.net.BindException: Address already in use: bind
理由:ポートが既に使用されているため、起動できなかった。
解決策:空いているポートを指定して起動する。
>java -jar wiremock-standalone-2.27.2.jar -port 8082
Request was not matched
Request was not matched
=======================
-----------------------------------------------------------------------------------------------------------------------
| Closest stub | Request |
-----------------------------------------------------------------------------------------------------------------------
|
GET | GET
/users/1 | /users/profile <<<<< URL does not match
|
|
-----------------------------------------------------------------------------------------------------------------------
mapping定義に該当するURLが存在しない場合、Request was not matchedというレスポンスが返却される。
右側の「Request」はあなたがRequestした内容、左側の「Closest stub」はmapping定義のうち最もRequestのURLに近いもの。
mapping定義ファイル(/mappings 配下のjson)を見直すこと。また、mapping定義ファイルを編集した後は、WireMockを再起動しないと反映されない。
MappingFileException:
Unrecognized field "yyy" (class StubMappingCollection), not marked as ignorable
>java -jar wiremock-standalone-2.27.2.jar
Exception in thread "main" com.github.tomakehurst.wiremock.standalone.MappingFileException: Error loading file D:\springhack\happy-library-mock\.\mappings\users.json:
Unrecognized field "mapping" (class com.github.tomakehurst.wiremock.stubbing.StubMappingCollection), not marked as ignorable
at com.github.tomakehurst.wiremock.standalone.JsonFileMappingsSource.loadMappingsInto(JsonFileMappingsSource.java:121)
at com.github.tomakehurst.wiremock.core.WireMockApp.loadMappingsUsing(WireMockApp.java:204)
at com.github.tomakehurst.wiremock.core.WireMockApp.loadDefaultMappings(WireMockApp.java:200)
at com.github.tomakehurst.wiremock.core.WireMockApp.<init>(WireMockApp.java:103)
at com.github.tomakehurst.wiremock.WireMockServer.<init>(WireMockServer.java:73)
at com.github.tomakehurst.wiremock.standalone.WireMockServerRunner.run(WireMockServerRunner.java:65)
at com.github.tomakehurst.wiremock.standalone.WireMockServerRunner.main(WireMockServerRunner.java:134)
{
"mapping": [
{
"request": {
"method": "GET",
"url": "/users"
},
"response": {
"status": 200,
"body": "Hello world! /users",
"headers": {
"Content-Type": "text/plain"
}
}
}
]
}
不適切なフィールド名が使用されている場合に出るエラー。
上記の場合は、jsonの2行目に"mapping"とあるが、正しくは"mappings"としなければならない。jsonの文法を見直してみよう。
MappingFileException: Unexpected character (']' (code 93)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
>java -jar wiremock-standalone-2.27.2.jar
Exception in thread "main" com.github.tomakehurst.wiremock.standalone.MappingFileException: Error loading file D:\springhack\happy-library-mock\.\mappings\v1\foo\fugo.json:
Unexpected character (']' (code 93)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: (String)"{
"mappings": [
{
"request": {
"method": "GET",
"url": "/hoge/fuga"
},
"response": {
"status": 200,
"body": "Hello world! /hoge/fuga",
"headers": {
"Content-Type": "text/plain"
}
}
},
]
}"; line: 16, column: 3]
at com.github.tomakehurst.wiremock.standalone.JsonFileMappingsSource.loadMappingsInto(JsonFileMappingsSource.java:121)
at com.github.tomakehurst.wiremock.core.WireMockApp.loadMappingsUsing(WireMockApp.java:204)
at com.github.tomakehurst.wiremock.core.WireMockApp.loadDefaultMappings(WireMockApp.java:200)
at com.github.tomakehurst.wiremock.core.WireMockApp.<init>(WireMockApp.java:103)
at com.github.tomakehurst.wiremock.WireMockServer.<init>(WireMockServer.java:73)
at com.github.tomakehurst.wiremock.standalone.WireMockServerRunner.run(WireMockServerRunner.java:65)
at com.github.tomakehurst.wiremock.standalone.WireMockServerRunner.main(WireMockServerRunner.java:134)
{
"mappings": [
{
"request": {
"method": "GET",
"url": "/hoge/fuga"
},
"response": {
"status": 200,
"body": "Hello world! /hoge/fuga",
"headers": {
"Content-Type": "text/plain"
}
}
},
]
}
JSONの文法上のエラーがある。[line: 16, column: 3]の前後を見直してみてください。
上の例では、「},」の「,」が不要です。フロントのJavaScriptでは使用できたり、推奨されたりする文法でも、WireMockではエラーとなることがあるので、気をつけてください。
HTTP ERROR 500 FileNotFoundException
FileNotFoundExceptionは、レスポンス用の.jsonが指定されたディレクトリに存在しない時に発生します。
「"bodyFileName": "bar.json",」と記述されているが、「__files/bar.json」がないという状況です。ディレクトリかbodyFileNameの値を見直してください。
レスポンスが文字化けする
レスポンスの.jsonファイルがSJISだと文字化けします。UTF-8を使用してください。
WireMock以外のモックサーバーソフトウェアの比較
ソフトウェア | 特徴など |
WireMock | |
MockServer | |
mockwebserver | |
OCMock |