WireMockの紹介
1. 概要
WireMock は、Webサービスをスタブおよびモックするためのライブラリです。 実際のWebサービスと同じように接続できるHTTPサーバーを構築します。
WireMock サーバーが動作しているときは、期待値を設定し、サービスを呼び出して、その動作を確認できます。
2. Mavenの依存関係
WireMockライブラリを利用できるようにするには、POMに次の依存関係を含める必要があります。
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>1.58</version>
<scope>test</scope>
</dependency>
3. プログラムで管理されるサーバー
このセクションでは、WireMockサーバーを手動で構成する方法について説明します。 すなわち JUnit自動構成のサポートなし。 使用法は、非常に単純なスタブによって示されます。
3.1. サーバーのセットアップ
WireMockサーバーは次のようにインスタンス化できます。
WireMockServer wireMockServer = new WireMockServer(String host, int port);
引数が指定されていない場合、サーバーホストはデフォルトで localhost になり、サーバーポートは8080になります。
次に、2つの簡単な方法を使用して、サーバーを起動および停止できます。
wireMockServer.start();
と:
wireMockServer.stop();
3.2. 基本的な使用法
WireMockライブラリは、最初に基本的な使用法によって示されます。ここでは、追加の構成なしで正確なURLのスタブが提供されます。 サーバーインスタンスを作成しましょう:
WireMockServer wireMockServer = new WireMockServer();
クライアントが接続する前に、WireMockサーバーが実行されている必要があります。
wireMockServer.start();
次に、Webサービスはスタブされます。
configureFor("localhost", 8080);
stubFor(get(urlEqualTo("/baeldung")).willReturn(aResponse().withBody("Welcome to Baeldung!")));
このチュートリアルでは、Apache HttpClient APIを使用して、サーバーに接続しているクライアントを表します。
CloseableHttpClient httpClient = HttpClients.createDefault();
その後、要求が実行され、応答がそれぞれ返されます。
HttpGet request = new HttpGet("http://localhost:8080/baeldung");
HttpResponse httpResponse = httpClient.execute(request);
ヘルパーメソッドを使用して、httpResponse変数をStringに変換します。
String responseString = convertResponseToString(httpResponse);
その変換ヘルパーメソッドの実装は次のとおりです。
private String convertResponseToString(HttpResponse response) throws IOException {
InputStream responseStream = response.getEntity().getContent();
Scanner scanner = new Scanner(responseStream, "UTF-8");
String responseString = scanner.useDelimiter("\\Z").next();
scanner.close();
return responseString;
}
次のコードは、サーバーが予期されたURLへの要求を受け取り、クライアントに到着する応答が正確に送信されたものであることを確認します。
verify(getRequestedFor(urlEqualTo("/baeldung")));
assertEquals("Welcome to Baeldung!", stringResponse);
最後に、WireMockサーバーを停止して、システムリソースを解放する必要があります。
wireMockServer.stop();
4. JUnit管理対象サーバー
セクション3とは対照的に、このセクションでは、JUnit Ruleを使用したWireMockサーバーの使用法を示します。
4.1. サーバーのセットアップ
WireMockサーバーは、@Ruleアノテーションを使用してJUnitテストケースに統合できます。 これにより、JUnitはライフサイクルを管理し、各テストメソッドの前にサーバーを起動し、メソッドが戻った後にサーバーを停止できます。
プログラムで管理されるサーバーと同様に、JUnitで管理されるWireMockサーバーは、指定されたポート番号を持つJavaオブジェクトとして作成できます。
@Rule
public WireMockRule wireMockRule = new WireMockRule(int port);
引数が指定されていない場合、サーバーポートはデフォルト値8080を取ります。 サーバーホスト(デフォルトは localhost )、およびその他の構成は、Optionsインターフェースを使用して指定できます。
4.2. URLマッチング
WireMockRule インスタンスを設定したら、次のステップはスタブを構成することです。 このサブセクションでは、正規表現を使用してサービスエンドポイントのRESTスタブを提供します。
stubFor(get(urlPathMatching("/baeldung/.*"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("\"testing-library\": \"WireMock\"")));
HTTPクライアントの作成、要求の実行、および応答の受信に移りましょう。
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet("http://localhost:8080/baeldung/wiremock");
HttpResponse httpResponse = httpClient.execute(request);
String stringResponse = convertHttpResponseToString(httpResponse);
上記のコードスニペットは、変換ヘルパーメソッドを利用しています。
private String convertHttpResponseToString(HttpResponse httpResponse) throws IOException {
InputStream inputStream = httpResponse.getEntity().getContent();
return convertInputStreamToString(inputStream);
}
これにより、別のプライベートメソッドが使用されます。
private String convertInputStreamToString(InputStream inputStream) {
Scanner scanner = new Scanner(inputStream, "UTF-8");
String string = scanner.useDelimiter("\\Z").next();
scanner.close();
return string;
}
スタブの動作は、以下のテストコードによって検証されます。
verify(getRequestedFor(urlEqualTo("/baeldung/wiremock")));
assertEquals(200, httpResponse.getStatusLine().getStatusCode());
assertEquals("application/json", httpResponse.getFirstHeader("Content-Type").getValue());
assertEquals("\"testing-library\": \"WireMock\"", stringResponse);
4.3. ヘッダーマッチングのリクエスト
次に、ヘッダーを照合してRESTAPIをスタブ化する方法を示します。 スタブ構成から始めましょう:
stubFor(get(urlPathEqualTo("/baeldung/wiremock"))
.withHeader("Accept", matching("text/.*"))
.willReturn(aResponse()
.withStatus(503)
.withHeader("Content-Type", "text/html")
.withBody("!!! Service Unavailable !!!")));
前のサブセクションと同様に、同じヘルパーメソッドを使用してHttpClientAPIを使用したHTTPインタラクションを示します。
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet("http://localhost:8080/baeldung/wiremock");
request.addHeader("Accept", "text/html");
HttpResponse httpResponse = httpClient.execute(request);
String stringResponse = convertHttpResponseToString(httpResponse);
次の検証とアサーションは、前に作成したスタブの機能を確認します。
verify(getRequestedFor(urlEqualTo("/baeldung/wiremock")));
assertEquals(503, httpResponse.getStatusLine().getStatusCode());
assertEquals("text/html", httpResponse.getFirstHeader("Content-Type").getValue());
assertEquals("!!! Service Unavailable !!!", stringResponse);
4.4. ボディマッチングをリクエストする
WireMockライブラリを使用して、ボディマッチングを使用してRESTAPIをスタブ化することもできます。 この種のスタブの構成は次のとおりです。
stubFor(post(urlEqualTo("/baeldung/wiremock"))
.withHeader("Content-Type", equalTo("application/json"))
.withRequestBody(containing("\"testing-library\": \"WireMock\""))
.withRequestBody(containing("\"creator\": \"Tom Akehurst\""))
.withRequestBody(containing("\"website\": \"wiremock.org\""))
.willReturn(aResponse()
.withStatus(200)));
次に、リクエストの本文として使用されるStringEntityオブジェクトを作成します。
InputStream jsonInputStream
= this.getClass().getClassLoader().getResourceAsStream("wiremock_intro.json");
String jsonString = convertInputStreamToString(jsonInputStream);
StringEntity entity = new StringEntity(jsonString);
上記のコードは、前に定義した変換ヘルパーメソッドの1つであるconvertInputStreamToStringを使用しています。
クラスパス上のwiremock_intro.jsonファイルの内容は次のとおりです。
{
"testing-library": "WireMock",
"creator": "Tom Akehurst",
"website": "wiremock.org"
}
HTTP要求と応答は、次のように構成および実行できます。
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost request = new HttpPost("http://localhost:8080/baeldung/wiremock");
request.addHeader("Content-Type", "application/json");
request.setEntity(entity);
HttpResponse response = httpClient.execute(request);
これは、スタブを検証するために使用されるテストコードです。
verify(postRequestedFor(urlEqualTo("/baeldung/wiremock"))
.withHeader("Content-Type", equalTo("application/json")));
assertEquals(200, response.getStatusLine().getStatusCode());
4.5. スタブの優先順位
前のサブセクションでは、HTTPリクエストが単一のスタブのみに一致する状況を扱います。 リクエストに一致するもの以上のものがある場合は、より複雑になります。 このような場合、デフォルトでは、最後に追加されたスタブが優先されます。 ただし、ユーザーはその動作をカスタマイズして、WireMockスタブをより詳細に制御できます。
優先レベルを設定する場合としない場合で、着信要求が2つの異なるスタブに同時に一致する場合のWireMockサーバーの動作を示します。 どちらのシナリオでも、次のプライベートヘルパーメソッドを使用します。
private HttpResponse generateClientAndReceiveResponseForPriorityTests() throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet("http://localhost:8080/baeldung/wiremock");
request.addHeader("Accept", "text/xml");
return httpClient.execute(request);
}
まず、優先度を考慮せずに2つのスタブを構成します。
stubFor(get(urlPathMatching("/baeldung/.*"))
.willReturn(aResponse()
.withStatus(200)));
stubFor(get(urlPathEqualTo("/baeldung/wiremock"))
.withHeader("Accept", matching("text/.*"))
.willReturn(aResponse()
.withStatus(503)));
次に、HTTPクライアントを作成し、上記のヘルパーメソッドを使用してリクエストを実行します。
HttpResponse httpResponse = generateClientAndReceiveResponseForPriorityTests();
次のコードスニペットは、リクエストが両方に一致する場合、前に定義されたものに関係なく、最後に構成されたスタブが適用されることを確認します。
verify(getRequestedFor(urlEqualTo("/baeldung/wiremock")));
assertEquals(503, httpResponse.getStatusLine().getStatusCode());
優先度レベルが設定されているスタブに移りましょう。数値が小さいほど優先度が高くなります。
stubFor(get(urlPathMatching("/baeldung/.*"))
.atPriority(1)
.willReturn(aResponse()
.withStatus(200)));
stubFor(get(urlPathEqualTo("/baeldung/wiremock"))
.atPriority(2)
.withHeader("Accept", matching("text/.*"))
.willReturn(aResponse()
.withStatus(503)));
HTTPリクエストの作成と実行:
HttpResponse httpResponse = generateClientAndReceiveResponseForPriorityTests();
次のコードは、優先度レベルの影響を検証します。ここで、最後に設定されたスタブの代わりに最初に設定されたスタブが適用されます。
verify(getRequestedFor(urlEqualTo("/baeldung/wiremock")));
assertEquals(200, httpResponse.getStatusLine().getStatusCode());
5. 結論
このチュートリアルでは、WireMockと、URL、リクエストヘッダー、本文のマッチングなど、さまざまな手法を使用してRESTAPIをテストするためにこのライブラリを設定および構成する方法を紹介しました。
すべての例とコードスニペットの実装は、GitHubプロジェクトにあります。