Wiremock 入门教程2 - 自定义mock内部逻辑
1. 为什么需要自定义mock逻辑
假设我们我们的远端依赖接口, 可以根据不同的入参响应不同的结果, 那么此时写死的mock请求和响应就不适用了, 此时我们便需要自定义mock内部的逻辑处理
2. 使用场景
例如, 我们内部依赖的接口是 POST http://somehost.com/submit/something, 此时按远端处理POST请求Request返回一个 '{name:aaa , ... ...}', 如果我们改变请求体, 那么它将返回其他请求, 这时我们将可以使用wiremock 中的自定义处理逻辑.
3. 代码
3.1. 环境搭建
请查看查看上一篇文章 Wiremock + Spring reactor的简单集成测试
3.2. 代码实现
3.2.1. Controller
没什么特殊的, 就是一个简单的控制器
@PostMapping(path = "/transform")
public Mono<ResponseEntity<String>> transform(@RequestBody final String requestBody) {
return dummyService.transform(requestBody)
.map(res -> {
log.info("response from remote server: {}", res);
return ResponseEntity.ok(res);
});
}
3.2.2. Service
使用webClient发送post请求地址/change/id, 请求远端数据
private static final String TRANSFORM_PATH = "/change/id";
public Mono<String> transform(String bodyValue) {
log.info("processing bodyValue, {}", bodyValue);
return webClient.post()
.uri(TRANSFORM_PATH)
.bodyValue(bodyValue)
.retrieve()
.bodyToMono(String.class);
}
3.2.3. Stub (定义mock行为)
这里和之前不同的地方是, 我们使用了.withTransformers(DummyResponseTransformer.DUMMY_TRANSFORMER), 这个Transformer 变是我们自定义mock服务器的处理逻辑入口, 我们继续来看这个Transformer张啥样
stubFor(post(urlEqualTo("/change/id")).willReturn(aResponse()
.withTransformers(DummyResponseTransformer.DUMMY_TRANSFORMER)
.withTransformerParameter("prefix", "Hello_")));
3.2.4. ResponseTransformer
可以看到, 上一步Stub中的 DummyResponseTransformer.DUMMY_TRANSFORMER 就是这个ResponseTransformer 的一个flag, 当stub注册到这个flag 将使用此Transformer, 也就是使用此逻辑来处理请求, 这个例子中,我们只是简单的拼装了 请求的body和参数作为返回
@Slf4j
public class DummyResponseTransformer extends ResponseTransformer {
// transformer 标签(name)
static final String DUMMY_TRANSFORMER = "post_request_to_dummy_transformer";
@Override
public Response transform(Request request, Response response, FileSource fileSource, Parameters parameters) {
String prefix = parameters.getString("prefix");
log.info("receive request id: {}, and prefix:{}", request.getBodyAsString(), prefix);
String newId = prefix + request.getBodyAsString();
return Response.response()
.headers(new com.github.tomakehurst.wiremock.http.HttpHeaders(HttpHeader.httpHeader(org.springframework.http.HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)))
.status(202)
.body("{\"id\":\"" + newId + "\"}")
.build();
}
//标签
@Override
public String getName() {
return DUMMY_TRANSFORMER;
}
//Non-global transformations
@Override
public boolean applyGlobally() {
return false;
}
}
3.2.5. 注入Transformer
为了加载Transformer到Spring, 我们需要定义一个配置, 实现WireMockConfigurationCustomizer接口
@Component
public class DummyWireMockConfigurationCustomizer implements WireMockConfigurationCustomizer {
@Override
public void customize(WireMockConfiguration config) {
config.extensions(DummyResponseTransformer.class);
}
}
3.3. 测试
@Test
void testTransformer() {
stubFor(post(urlEqualTo("/change/id")).willReturn(aResponse()
.withTransformers(DummyResponseTransformer.DUMMY_TRANSFORMER)
.withTransformerParameter("prefix", "Hello_")));
webTestClient
.post()
.uri("/test/transform")
.bodyValue("666")
.exchange()
.expectStatus().isEqualTo(HttpStatus.OK)
.expectBody(String.class)
.consumeWith(stringEntityExchangeResult -> {
String responseBody = stringEntityExchangeResult.getResponseBody();
log.info(responseBody);
Assertions.assertEquals(responseBody, "{\"id\":\"Hello_666\"}");
});
}
4. 完整代码
https://github.com/wallisnow/wiremock_spring_reactor
5. 结语
Wiremock 定制化的mock内部逻辑处理可以方便我们根据外部已知的条件来定义我们的mock服务器, 本例中实现的是response transformer, 它还提供了其他的一些 定制化的Extension, 可以查看官方文档: http://wiremock.org/docs/extending-wiremock/. 但是这里有提供的代码有一个缺点, 就是这个transformer 似乎只能有一个, 那么我们就需要想办法注入多个transformer 来实现多种transform, 后续我们将实现这个需求