Wiremock:如何匹配没有特定 属性 的 JSON 请求?

Wiremock: how to match a JSON request that does NOT have a specific property?

我正在尝试模拟一个 API 调用,该调用在 POST 中接受一个 JSON 主体,它有两种可能的响应:

  1. 如果正文包含 SearchCenter 属性,请回答 A
  2. 如果正文不包含 SearchCenter,请使用响应 B
  3. 进行回答

在 Wiremock 文档的 Request Matching 章节中,它只展示了如何 积极地 匹配 JSON,它没有展示如何匹配缺失的属性。

带有 SearchCenter 的示例请求:

{
    "GeoCoordinatesResponseFormat": "DecimalDegree",
    "ProviderID": "bla bla",
    "SearchCenter": {
        "GeoCoordinates": {
            "DecimalDegree": {
                "Latitude": "{{search_lat}}",
                "Longitude": "{{search_lon}}"
            }
        },
        "Radius": {{search_radius}}
    }
}

没有 SearchCenter 的示例请求:

{
    "GeoCoordinatesResponseFormat": "DecimalDegree",
    "ProviderID": "bla bla"
}

编辑:我可能已经超前了——我认为有一个更简单的匹配解决方案。您可以使用 negative matching with regex。 (Negative Lookahead) 我仍然认为我更喜欢优先级方法。

stubFor(any(urlPathEqualTo("/some-endpoint"))
    .withRequestBody(matchingJsonPath("$.?!SearchCenter"))
    .willReturn(ok("Body does not contain Search Center"));

stubFor(any(urlPathEqualTo("/some-endpoint"))
    .withRequestBody(matchingJsonPath("$.SearchCenter"))
    .willReturn(ok("Body does contain Search Center"));

您可以通过两种方式完成此操作。第一个将使用正则表达式 matcher/not 匹配器。假设您使用的是存根...

stubFor(any(urlPathEqualTo("/some-endpoint"))
    .withRequestBody(notMatching("\"SearchCenter\": \{ .* \}"))
    .willReturn(ok("Body does not contain Search Center"));

stubFor(any(urlPathEqualTo("/some-endpoint"))
    .withRequestBody(matchingJsonPath("$.SearchCenter"))
    .willReturn(ok("Body does contain Search Center"));

这会在不匹配时进行正则表达式匹配以检查该字段是否不存在,然后JSON 路径匹配以检查该字段是否存在。 (我没有测试实际代码,所以正则表达式匹配 / JSON 路径可能需要一些调整。)

不过,我认为更好的解决方案是让一个响应更具体地匹配 return,而另一个响应更不具体地匹配 return。我们可以通过优先级来实现这一点。

stubFor(any(urlPathEqualTo("/some-endpoint"))
    .atPriority(1)
    .withRequestBody(matchingJsonPath("$.SearchCenter"))
    .willReturn(ok("Body does contain Search Center"));

stubFor(any(urlPathEqualTo("/some-endpoint"))
    .atPriority(2)
    .willReturn(ok("Body does not contain Search Center"));

Information on Priorities can be found here。 Priorities 上的 tl;dr 是它们强制 WireMock 在其他匹配项之前检查某些匹配项。在这种情况下,我们将检查请求正文是否包含我们想要的字段 ("Search Center"),如果包含,我们将 return 匹配。如果我们有其他具有相同优先级 (1) 的存根,那么在进入下一个优先级之前也会检查这些存根。如果没有找到我们要匹配的字段,我们将转到下一个优先级。因为 Priority 2 的存根不需要匹配 Request Body 中的 JSON Path,所以我们会匹配

我更喜欢两次特定匹配的优先级,这仅仅是因为我喜欢 "fallback" 通用存根提供的行为,其中对“/some-endpoint”的任何调用都将通过通用响应来实现。

为了匹配缺失的 JSON 属性,您可以将 matchingJsonPath 运算符与 absent() 结合使用,如下所示:

.withRequestBody(matchingJsonPath("$.SearchCenter", absent()))