WireMockはresponse-templatingによりレスポンスを書き換えられる。以下にspring-bootの@SpringBootTest
を前提にしたサンプルコード・使い方について書く。
ソースコード
build.gradle
plugins { id 'org.springframework.boot' version '2.7.2' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } ext { set('springCloudVersion', "2021.0.3") } dependencies { implementation 'org.springframework.boot:spring-boot-starter-webflux' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-stub-runner' } dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } } tasks.named('test') { useJUnitPlatform() }
application.properties
外部APIを想定したテストなのでsrc/main/resources/application.properties
にURLを定義しておく。自動テスト実行時にはWireMockのモックサーバーのURLになる。
external.api.url=http://localhost:12345
java
パスをそのままWireMockに投げてレスポンスもそのまま返すだけのマッピングを作っておく。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; @RestController @SpringBootApplication() public class SampleWireMockApplication { WebClient client; SampleWireMockApplication(WebClient.Builder webClientBuilder, Environment env) { this.client = webClientBuilder.baseUrl(env.getProperty("external.api.url")).build(); } @GetMapping("/**") public Flux<String> sample(ServerWebExchange exchange) { return client .get().uri(exchange.getRequest().getPath().value()) .retrieve() .bodyToFlux(String.class); } public static void main(String[] args) { SpringApplication.run(SampleWireMockApplication.class, args); } }
SpringBootTestのテストコード
上記のcontrollerにアクセスしてレスポンスを返すだけのテストコードを書く。本来はここで各種expectをするのだけど今回そこは主題ではないので省略する。
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; import org.springframework.test.web.reactive.server.WebTestClient; @SpringBootTest(properties = { "external.api.url=http://localhost:${wiremock.server.port}" }, webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureWireMock(port = 0) public class ApplicationTest { @Autowired WebTestClient client; @Test void testSample() { String result = client .get().uri("/hoge") .exchange() .returnResult(String.class) .getResponseBody() .blockFirst(); System.out.println(result); } }
WireMock
mapping
/src/test/resources/mappings/sample-mapping.json
マッピングファイルを作る。
{ "request": { "method": "GET", "urlPathPattern": "/(.*)" }, "response": { "status": "200", "body": "{{request.path}}", "transformers": ["response-template"] } }
実行結果
これを実行するとレスポンスに/hoge
と返ってくる。
response-template
基本的な使い方
まずtransformers
にresponse-template
の追加が必要。これによりresponse-templatingのThe request modelの各種組み込み変数やhelper関数が使用可能となる。以降、マッピングファイルのサンプルコードはresponse
部分のみに省略。
"response": { "status": "200", "body": "{{request.path}}", "transformers": ["response-template"] }
ボディファイルを動的に変更
例えば、以下のようにパスで返すボディファイルを変更したい、とする。
/hoge.json
->__files/sample/hoge.json
/foo.json
->__files/sample/foo.json
"response": { "status": "200", "bodyFileName": "sample/{{request.path.[0]}}", "transformers": ["response-template"] }
ボディファイルの中身を動的に変更
ボディファイルの中身にも{{request.path.[0]}}
などを書ける。
まず以下のようにボディファイルを返すマッピングを作る。
"response": { "status": "200", "bodyFileName": "sample/foo.json", "transformers": ["response-template"] }
次にボディファイルの中身をリクエストパスで動的に書き換える。
{ "id": "{{request.path}}" }
これで例えば/hoge-path
にアクセスするとレスポンスボディは{ "id": "/hoge-path"}
が返ってくる。
ドキュメント
- response-templating - 他にも色々な使い方がある。