如何在 WireMock 中捕获已存根请求的原始请求体

本文介绍在 wiremock 中精准捕获被 stubbed 的 http 请求(尤其是 post)原始请求体的方法,通过 serveevent 机制获取真实请求内容,并结合 xmlunit 等工具进行灵活断言,规避 `equaltoxml()` 等内置匹配器过于严格的限制。

WireMock 本身不提供类似 Mockito ArgumentCaptor 的声明式参数捕获机制,但其强大的运行时事件追踪能力(ServeEvent)可完美替代该需求。核心思路是:为 stub 显式分配唯一 ID,待测试请求执行后,通过 getAllServeEvents() 查询该 stub 对应的完整请求记录,进而提取原始请求体(包括未解析的 XML 字符串、JSON 或任意文本格式)。

✅ 推荐实现步骤

  1. 为 stub 分配唯一 UUID
    在定义 stub 时,调用 .withId(...) 方法绑定一个预设 UUID(注意:必须使用 java.util.UUID.fromString() 构造,不能用 UUID.randomUUID() 动态生成,否则无法后续查询):
String STUB_ID = "a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8"; // 预定义固定 UUID
stubFor(
    post(urlPathEqualTo(getUploadEndpoint()))
        .willReturn(aResponse().withStatus(HttpStatus.OK.value()))
).withId(UUID.fromString(STUB_ID));
  1. 触发被测请求
    执行你的业务逻辑(例如调用上传接口),确保该请求命中上述 stub。

  2. 检索并断言请求体
    使用 ServeEventQuery.forStubMapping() 查询该 stub ID 对应的所有服务事件(通常仅含 1 条),从中提取 request.getBodyAsString():

List events = getAllServeEvents(ServeEventQuery.forStubMapping(UUID.fromString(STUB_ID)));
assertThat(events).hasSize(1);

String actualBody = events.get(0).getRequest().getBodyAsString();
// 此时 actualBody 即为客户端发送的原始请求体字符串(含换行、空格、无根标签等自由格式)
  1. 使用 XMLUnit 进行语义化比对(推荐)
    若请求体为 XML,避免使用 equalToXml() 的严格校验,改用 XMLUnit 提供的宽松比较:
import org.xmlunit.diff.Diff;
import org.xmlunit.builder.Di

ffBuilder; Diff diff = DiffBuilder.compare(expectedXml) .withTest(actualBody) .ignoreWhitespace() // 忽略空白符差异 .normalizeWhitespace() // 标准化空白(如换行转空格) .checkForSimilar() // 启用“相似性”而非“完全相等”检查 .build(); assertThat(diff.hasDifferences()).isFalse();

⚠️ 注意事项与最佳实践

  • UUID 必须全局唯一且固定:同一测试中多个 stub 不可复用相同 ID;不同测试间建议使用 @BeforeEach 生成新 UUID 并清理事件(resetAll())。
  • 事件查询时机:确保在请求完成后再调用 getAllServeEvents(),必要时加入短延时或使用 await()(若集成 TestContainers 或异步场景)。
  • 资源清理:测试结束后建议调用 resetAll() 清除所有 stub 和事件,避免跨测试污染。
  • 非 XML 场景:对 JSON 可用 Jackson 的 JsonNode 深度比较;对纯文本可结合正则或 containsPattern() 断言关键字段。
  • 性能考量:ServeEvent 默认启用,但高并发压测中可考虑关闭(WireMockConfiguration.options().disableRequestJournal()),单元测试中无需担心。

该方案不依赖 WireMock 内置匹配逻辑,完全基于真实请求快照,兼顾灵活性与可靠性,是验证复杂请求体(如带注释的 XML、格式化 JSON、含动态时间戳的 payload)的首选实践。