きり丸の技術日記

技術・エンジニアのイベント・資格等はこちらにまとめる予定です

Wiremockをモックサーバとして使用してJavaの単体テストをする

弊社ではモックサーバにWiremockを使用しています。

この記事ではWiremockを知ってもらうきっかけを提供することを目的としています。詳しいことは他の方の記事を参考にした方が良いでしょう。

ゴール

  • WiremockのモックサーバでJUnitでテストする

Wiremockのスタンドアロンで起動する機能については、今回は紹介しません。スタンドアロンなら別のいいツールあるかもしれないので。

Wiremockとは

WireMockはHTTPモックサーバー。リクエスト回数やリクエストJSONを確認することもできる。

スタンドアロンとしても立ち上げることができるので、JUnitとの連携だけでなくE2Eテストや検証環境でも使用することができる。

環境

  • Java
    • 15
  • org.springframework.boot
    • 2.4.0
  • com.github.tomakehurst:wiremock-jre8
    • 2.27.2
  • ru.lanwen.wiremock:wiremock-junit5
    • 1.3.1

単体テストでの使い方

Wiremockが使えるように依存関係に含める

使用できるように依存関係に含めます。デフォルトだとJUnit4の記述しかできないので、JUnit5でも使用できるように関連ライブラリも依存関係に含めます。

Gradleでの記述方法。

testImplementation "com.github.tomakehurst:wiremock-jre8:2.27.2"
testImplementation "ru.lanwen.wiremock:wiremock-junit5:1.3.1"

Wiremockをテストクラスで使えるようにする

WiremockResolver.classを読み込みます。

@ExtendWith(WiremockResolver.class)

Wiremockサーバを初期セットアップする


テストクラスのコンストラクタを使用します。

@WiremockResolver.Wiremockをパラメータに付けることで、初期化対象となります。

ランダムポートで生成されるので、テストターゲットに対してパラメータを渡してあげることで並列実行等もできるようになります。

  private WireMockServer server;

  ZipCloudClientImplTests(@WiremockResolver.Wiremock WireMockServer server) {
    this.server = server;
  }
  @BeforeEach
  void setup() {
    ZipCloudClientProperties properties = new ZipCloudClientProperties();
    properties.setSchema("http");
    properties.setHost("localhost");
    properties.setPort(server.port());
    properties.setPath("/api/search");

    RestOperationFactory restOperationFactory = new RestOperationFactory(restTemplateBuilder, new RestTemplateInterceptor());
    RestOperations restOperations = restOperationFactory.createRestOperations(properties);

    target = new ZipCloudClientImpl(properties, restOperations);
  }

モックをセットする


あとはWiremockに設定するのみです。

こちらを設定したうえで、テストを実施すると対向システムをモックサーバとした状態でテストできます。

次の記載方法は、特定のURLとクエリパラメータ時に、特定のResponseBodyを返却する書き方となります。

    String responseBody =
        """
            {
              "message":null,
              "results": [{
                "address1":"神奈川県",
                "address2" : "厚木市",
                "address3" : "中町",
                "kana1" : "カナガワケン",
                "kana2" : "アツギシ",
                "kana3" : "ナカチョウ",
                "prefcode" : "14",
                "zipcode" : "2430018"
              }],
              "status": 200
            }""";

    server.stubFor(
        get("/api/search?zipcode=2430018").willReturn(
            aResponse()
                .withStatus(200)
                .withHeader("Content-Type", "text/plain")
                .withBody(responseBody)
        )
    );

リクエストJSONを比較したい時には、withRequestBodyを使用します。※ソースコードでは比較していません。

    String requestBody =
        """
            {
              "message":null,
              "results": [{
                "address1":"神奈川県",
                "address2" : "厚木市",
                "address3" : "中町",
                "kana1" : "カナガワケン",
                "kana2" : "アツギシ",
                "kana3" : "ナカチョウ",
                "prefcode" : "14",
                "zipcode" : "2430018"
              }],
              "status": 200
            }""";

    server.stubFor(
        post("/api/search")
            .withRequestBody(
                equalToJson(requestBody)
            )

ソースコード

終わりに

Wiremockが使えると単体テストができるようになるので便利です。

もちろん、できるだけ本番環境でテストできることが最高ですが、相手のサービスのメンテナンス時間が原因でテスト失敗するFlakyなテストになってしまいます。実行するたびに課金されるようなAPIを実行しても厳しいですしね。

知らないだけでもっと便利なJavaのモックサーバはあるかもしれませんが、Spring公式でも紹介されている以上、便利なものでしょう。

JavaとWiremockで調べる人が多いとは思いませんが、一助になればと思います。


この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。

参考

Wiremock公式サイト wiremock.org

Spring公式のWiremockの使用方法 cloud.spring.io

f:id:nainaistar:20211009232958p:plain