WireMockシナリオの使用

  • link:/category/testing/ [テスト]

1. 概要

このクイックチュートリアルでは、WireMockを使用してステートフルHTTPベースのAPIをテストする方法を示します。
ライブラリの使用を開始するには、まずlink:/introduction-to-wiremock[Introduction to WireMock]チュートリアルをご覧ください。

2. Mavenの依存関係

https://search.maven.org/search?q=a:wiremock[WireMock library]を利用できるようにするには、次の依存関係をPOMに含める必要があります。
<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock</artifactId>
    <version>2.21.0</version>
    <scope>test</scope>
</dependency>

3. モックしたいサンプルAPI

Wiremockのシナリオのコンセプトは、* REST APIのさまざまな状態のシミュレーションを支援することです*。 これにより、使用しているAPIが状態によって異なる動作をするテストを作成できます。
これを説明するために、実用的な例を見てみましょう。「Java Tip」サービスは、__ / java-tip request__endpointをリクエストするたびにJavaに関する別のヒントを提供します。
ヒントを頼むと、戻ってきて_text / plain_を受け取ります:
"use composition rather than inheritance"
再度呼び出した場合、別のヒントが表示されます。

4. シナリオ状態の作成

WireMockに_“ / java-tip” _エンドポイントのスタブを作成させる必要があります。 スタブはそれぞれ、モックAPIの3つの状態のいずれかに対応する特定のテキストを返します。
public class WireMockScenarioExampleIntegrationTest {
    private static final String THIRD_STATE = "third";
    private static final String SECOND_STATE = "second";
    private static final String TIP_01 = "finally block is not called when System.exit()"
      + " is called in the try block";
    private static final String TIP_02 = "keep your code clean";
    private static final String TIP_03 = "use composition rather than inheritance";
    private static final String TEXT_PLAIN = "text/plain";

    static int port = 9999;

    @Rule
    public WireMockRule wireMockRule = new WireMockRule(port);

    @Test
    public void changeStateOnEachCallTest() throws IOException {
        createWireMockStub(Scenario.STARTED, SECOND_STATE, TIP_01);
        createWireMockStub(SECOND_STATE, THIRD_STATE, TIP_02);
        createWireMockStub(THIRD_STATE, Scenario.STARTED, TIP_03);

    }

    private void createWireMockStub(String currentState, String nextState, String responseBody) {
        stubFor(get(urlEqualTo("/java-tip"))
          .inScenario("java tips")
          .whenScenarioStateIs(currentState)
          .willSetStateTo(nextState)
          .willReturn(aResponse()
            .withStatus(200)
            .withHeader("Content-Type", TEXT_PLAIN)
            .withBody(responseBody)));
    }

}
上記のクラスでは、WireMockのJUnitルールクラス_WireMockRule_を使用します。 これにより、JUnitテストの実行時にWireMockサーバーがセットアップされます。
*次に、WireMockの_stubFor_メソッドを使用して、後で使用するスタブを作成します。*
スタブの作成時に使用される主要なメソッドは次のとおりです。
  • whenScenarioStateIs:シナリオの状態を定義します
    WireMockがこのスタブを使用するために

  • willSetStateTo:WireMockが状態を設定する値を提供します
    このスタブが使用された後

    シナリオの初期状態は_Scenario.STARTED_です。 そのため、状態が_Scenario.STARTED._のときに使用されるスタブを作成します。これにより、状態がSECOND_STATEに移行します。
    また、SECOND_STATEからTHIRD_STATEに移動し、最後にTHIRD_STATEから_Scenario.STARTED._に戻るスタブを追加します。したがって、_ / java-tip_エンドポイントを呼び出し続けると、状態は次のように変わります。
  • Scenario.STARTED→ SECOND_STATE→ THIRD_STATE→ Scenario.STARTED *

5. シナリオの使用

WireMockシナリオを使用するには、_ / java-tip_エンドポイントを繰り返し呼び出します。 したがって、次のようにテストクラスを変更する必要があります。
    @Test
    public void changeStateOnEachCallTest() throws IOException {
        createWireMockStub(Scenario.STARTED, SECOND_STATE, TIP_01);
        createWireMockStub(SECOND_STATE, THIRD_STATE, TIP_02);
        createWireMockStub(THIRD_STATE, Scenario.STARTED, TIP_03);

        assertEquals(TIP_01, nextTip());
        assertEquals(TIP_02, nextTip());
        assertEquals(TIP_03, nextTip());
        assertEquals(TIP_01, nextTip());
    }

    private String nextTip() throws ClientProtocolException, IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet request = new HttpGet(String.format("http://localhost:%s/java-tip", port));
        HttpResponse httpResponse = httpClient.execute(request);
        return firstLineOfResponse(httpResponse);
    }

    private static String firstLineOfResponse(HttpResponse httpResponse) throws IOException {
        try (BufferedReader reader = new BufferedReader(
          new InputStreamReader(httpResponse.getEntity().getContent()))) {
            return reader.readLine();
        }
    }
_nextTip()_メソッドは_ / java-tip_エンドポイントを呼び出してから、応答を_String_として返します。 したがって、各_assertEquals()_呼び出しでそれを使用して、呼び出しが実際にシナリオを取得して異なる状態を循環することを確認します。

6. 結論

この記事では、WireMockシナリオを使用して、状態に応じて応答を変更するAPIをモックする方法を説明しました。
いつものように、このチュートリアルで使用されるすべてのコードは、https://github.com/eugenp/tutorials/tree/master/testing-modules/rest-testing [GitHubで]から入手できます。