事象
商用で動いているSpring BootのAppを改修した。
AppにはRestTemplateを使って他の連携先システムのREST APIを呼びにいく箇所があり、該当箇所を含む単体テストはWireMockでモックサーバを立てて実施していた。
改修に応じてテストを追加した所、既存のテストが突然
NoHttpResponseException:[server] failed to respond
などと例外を吐いてコケるようになった。
テストを単体で実行すると通り、通しで実行するとコケるという状態のため、テスト自体のミスでは無い模様。
ということで調査開始。
原因
WireMockへアクセスするAppのHttp Clientに、HttpURLConnectionを使用している場合に発生するバグらしい。
https://github.com/tomakehurst/wiremock/issues/97
SpringのRestTemplateも内部的にはHttpURLConnectionを使っているので該当。
対策
spring-cloud-contract-wiremockを使う。
https://github.com/tomakehurst/wiremock/issues/97
同issueに何種類かの対策が示されているので、お気に召すものを採用すれば良いと思われる。
一応の選定基準は以下の様な感じ。
-
Spring Bootのバージョンを上げる or HttpClientを変える
商用で動いているAppなので、テストのために構成変更は基本NG→✕ -
HttpClientのconnection reuseを無効化
設定場所が分からないし、Appの動作に影響出そう→✕ -
spring-cloud-contract-wiremockの利用
テストのライブラリ変更だけで完結→○
spring-cloud-contract-wiremockは名前の通り内部でwireMockを利用しているので、テストコードの変更も最小限で済みました。
具体的には、サーバ設定の記法を変更して、既存のテスト用resourceのディレクトリを指定してやるだけ。
詳しい使い方は公式参照
public class ExampleUnitTest {
@Rule
public WireMockRule wireMockRule = new WireMockRule(8080);
....
@AutoConfigureWireMock(port = 8080, stubs = "classpath*:/META-INF/**/mappings/**/*.json")
public class ExampleUnitTest {
....
上記の通り、私の場合はstubs =
で指定しているテスト用resourceのパスをよしなにしてやるだけで既存のテストコードがそのままパスするようになりました。