SpringCloud 引用响应中的请求

2023-12-12 18:17 更新

最好的情况是提供固定值,但是有时您需要在响应中引用一个请求。

如果您使用Groovy DSL编写合同,则可以使用fromRequest()方法,该方法使您可以从HTTP请求中引用一堆元素。您可以使用以下选项:

  • fromRequest().url():返回请求URL和查询参数。
  • fromRequest().query(String key):返回具有给定名称的第一个查询参数。
  • fromRequest().query(String key, int index):返回具有给定名称的第n个查询参数。
  • fromRequest().path():返回完整路径。
  • fromRequest().path(int index):返回第n个路径元素。
  • fromRequest().header(String key):返回具有给定名称的第一个标头。
  • fromRequest().header(String key, int index):返回具有给定名称的第n个标题。
  • fromRequest().body():返回完整的请求正文。
  • fromRequest().body(String jsonPath):从请求中返回与JSON路径匹配的元素。

如果您使用的是YAML合同定义,则必须使用带有自定义Spring Cloud Contract函数Handlebars {{{ }}}符号来实现此目的。

  • {{{ request.url }}}:返回请求URL和查询参数。
  • {{{ request.query.key.[index] }}}:返回具有给定名称的第n个查询参数。例如,键foo的第一个条目{{{ request.query.foo.[0] }}}
  • {{{ request.path }}}:返回完整路径。
  • {{{ request.path.[index] }}}:返回第n个路径元素。例如,首次输入` {{{request.path。[0] }}}
  • {{{ request.headers.key }}}:返回具有给定名称的第一个标头。
  • {{{ request.headers.key.[index] }}}:返回具有给定名称的第n个标头。
  • {{{ request.body }}}:返回完整的请求正文。
  • {{{ jsonpath this 'your.json.path' }}}:从请求中返回与JSON路径匹配的元素。例如json路径$.foo-{{{ jsonpath this '$.foo' }}}

考虑以下合同:

YAML。 

request:
  method: GET
  url: /api/v1/xxxx
  queryParameters:
    foo:
      - bar
      - bar2
  headers:
    Authorization:
      - secret
      - secret2
  body:
    foo: bar
    baz: 5
response:
  status: 200
  headers:
    Authorization: "foo {{{ request.headers.Authorization.0 }}} bar"
  body:
    url: "{{{ request.url }}}"
    path: "{{{ request.path }}}"
    pathIndex: "{{{ request.path.1 }}}"
    param: "{{{ request.query.foo }}}"
    paramIndex: "{{{ request.query.foo.1 }}}"
    authorization: "{{{ request.headers.Authorization.0 }}}"
    authorization2: "{{{ request.headers.Authorization.1 }}"
    fullBody: "{{{ request.body }}}"
    responseFoo: "{{{ jsonpath this '$.foo' }}}"
    responseBaz: "{{{ jsonpath this '$.baz' }}}"
    responseBaz2: "Bla bla {{{ jsonpath this '$.foo' }}} bla bla"

运行JUnit测试生成将导致类似于以下示例的测试:

// given:
 MockMvcRequestSpecification request = given()
   .header("Authorization", "secret")
   .header("Authorization", "secret2")
   .body("{\"foo\":\"bar\",\"baz\":5}");

// when:
 ResponseOptions response = given().spec(request)
   .queryParam("foo","bar")
   .queryParam("foo","bar2")
   .get("/api/v1/xxxx");

// then:
 assertThat(response.statusCode()).isEqualTo(200);
 assertThat(response.header("Authorization")).isEqualTo("foo secret bar");
// and:
 DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
 assertThatJson(parsedJson).field("['fullBody']").isEqualTo("{\"foo\":\"bar\",\"baz\":5}");
 assertThatJson(parsedJson).field("['authorization']").isEqualTo("secret");
 assertThatJson(parsedJson).field("['authorization2']").isEqualTo("secret2");
 assertThatJson(parsedJson).field("['path']").isEqualTo("/api/v1/xxxx");
 assertThatJson(parsedJson).field("['param']").isEqualTo("bar");
 assertThatJson(parsedJson).field("['paramIndex']").isEqualTo("bar2");
 assertThatJson(parsedJson).field("['pathIndex']").isEqualTo("v1");
 assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5);
 assertThatJson(parsedJson).field("['responseFoo']").isEqualTo("bar");
 assertThatJson(parsedJson).field("['url']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2");
 assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla");

如您所见,响应中已正确引用了请求中的元素。

生成的WireMock存根应类似于以下示例:

{
  "request" : {
    "urlPath" : "/api/v1/xxxx",
    "method" : "POST",
    "headers" : {
      "Authorization" : {
        "equalTo" : "secret2"
      }
    },
    "queryParameters" : {
      "foo" : {
        "equalTo" : "bar2"
      }
    },
    "bodyPatterns" : [ {
      "matchesJsonPath" : "$[?(@.['baz'] == 5)]"
    }, {
      "matchesJsonPath" : "$[?(@.['foo'] == 'bar')]"
    } ]
  },
  "response" : {
    "status" : 200,
    "body" : "{\"authorization\":\"{{{request.headers.Authorization.[0]}}}\",\"path\":\"{{{request.path}}}\",\"responseBaz\":{{{jsonpath this '$.baz'}}} ,\"param\":\"{{{request.query.foo.[0]}}}\",\"pathIndex\":\"{{{request.path.[1]}}}\",\"responseBaz2\":\"Bla bla {{{jsonpath this '$.foo'}}} bla bla\",\"responseFoo\":\"{{{jsonpath this '$.foo'}}}\",\"authorization2\":\"{{{request.headers.Authorization.[1]}}}\",\"fullBody\":\"{{{escapejsonbody}}}\",\"url\":\"{{{request.url}}}\",\"paramIndex\":\"{{{request.query.foo.[1]}}}\"}",
    "headers" : {
      "Authorization" : "{{{request.headers.Authorization.[0]}}};foo"
    },
    "transformers" : [ "response-template" ]
  }
}

发送请求(例如合同的request部分中提出的请求)会导致发送以下响应正文:

{
  "url" : "/api/v1/xxxx?foo=bar&foo=bar2",
  "path" : "/api/v1/xxxx",
  "pathIndex" : "v1",
  "param" : "bar",
  "paramIndex" : "bar2",
  "authorization" : "secret",
  "authorization2" : "secret2",
  "fullBody" : "{\"foo\":\"bar\",\"baz\":5}",
  "responseFoo" : "bar",
  "responseBaz" : 5,
  "responseBaz2" : "Bla bla bar bla bla"
}
此功能仅适用于版本大于或等于2.5.1的WireMock。Spring Cloud Contract验证程序使用WireMock的response-template响应转换器。它使用把手将“ Mustache {{{ }}}”模板转换为适当的值。此外,它注册了两个帮助程序功能:
  • escapejsonbody:以可以嵌入JSON的格式转义请求正文。
  • jsonpath:对于给定的参数,在请求正文中找到一个对象。


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号