HTTP Contracts
此页面描述了契约中最重要的 HTTP 相关部分。
This page describes most important HTTP related parts of the contract.
HTTP Top-Level Elements
HTTP Top-Level Elements
可以在契约定义的顶层闭包中调用以下方法:
You can call the following methods in the top-level closure of a contract definition:
-
request
: Mandatory -
response
: Mandatory -
priority
: Optional
以下示例展示了如何定义一个 HTTP 请求契约:
The following example shows how to define an HTTP request contract:
Unresolved directive in _dsl-http-top-level-elements.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[]
Unresolved directive in _dsl-http-top-level-elements.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
Unresolved directive in _dsl-http-top-level-elements.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
...
Unresolved directive in _dsl-http-top-level-elements.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
...
Unresolved directive in _dsl-http-top-level-elements.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[]
Unresolved directive in _dsl-http-top-level-elements.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[]
如果你想让你的合同有更高的优先级,你需要给 priority
标签或方法传递一个较小的数值。例如,值为 5
的 priority
比值为 10
的 priority
具有更高的优先级。
If you want to make your contract have a higher priority,
you need to pass a lower number to the priority
tag or method. For example, a priority
with
a value of 5
has higher priority than a priority
with a value of 10
.
HTTP Request
HTTP Request
HTTP 协议仅要求在请求中指定方法和 URL。相同的的信息在契约的请求定义中是强制性的。
The HTTP protocol requires only the method and the URL to be specified in a request. The same information is mandatory in request definition of the contract.
以下示例展示了一个请求契约:
The following example shows a contract for a request:
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[]
你可以指定一个绝对而不是相对 url
,但是使用 urlPath
是推荐的方式,因为这样做使测试独立于主机。
You can specify an absolute rather than a relative url
, but using urlPath
is
the recommended way, as doing so makes the tests be host-independent.
以下示例使用了 url
:
The following example uses url
:
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract_rest_with_path.yml[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[]
request
可能包含查询参数,如下例所示(该示例使用了 urlPath
):
request
may contain query parameters, as the following example (which uses urlPath
) shows:
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
...
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[]
如果一个查询参数在合同中丢失,并不意味着我们期望在查询参数丢失的情况下匹配请求。恰恰相反,这意味着查询参数不存在并不要求匹配请求。
If a query parameter is missing in the contract it doesn’t mean that we expect a request to be matched if the query parameter is missing. Quite the contrary, that means that the query parameter is not necessary to be there for the request to be matched.
request
可能包含额外的请求头,如下例所示:
request
can contain additional request headers, as the following example shows:
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
...
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[]
request
可能包含额外的请求 cookie,如下例所示:
request
may contain additional request cookies, as the following example shows:
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
...
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[]
request
可能包含一个请求正文,如下例所示:
request
may contain a request body, as the following example shows:
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
...
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[]
request
可能包含多部分元素。要包含多部分元素,请使用 multipart
方法/章节,如下例所示:
request
can contain multipart elements. To include multipart elements, use the
multipart
method/section, as the following examples show:
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/yml/contract_multipart.yml[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_multipart.java[]
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/resources/kotlin/multipart.kts[]
在前面的示例中,我们通过以下两种方式定义了参数:
In the preceding example, we defined parameters in either of two ways:
-
Directly, by using the map notation, where the value can be a dynamic property (such as
formParameter: $(consumer(…), producer(…))
). -
By using the
named(…)
method that lets you set a named parameter. A named parameter can set aname
andcontent
. You can call it either by using a method with two arguments, such asnamed("fileName", "fileContent")
, or by using a map notation, such asnamed(name: "fileName", content: "fileContent")
.
-
The multipart parameters are set in the
multipart.params
section. -
The named parameters (the
fileName
andfileContent
for a given parameter name) can be set in themultipart.named
section. That section contains theparamName
(the name of the parameter),fileName
(the name of the file),fileContent
(the content of the file) fields. -
The dynamic bits can be set in the
matchers.multipart
section.-
For parameters, use the
params
section, which can acceptregex
or apredefined
regular expression. -
For named parameters, use the
named
section where you first define the parameter name withparamName
. Then you can pass the parametrization of eitherfileName
orfileContent
in aregex
or in apredefined
regular expression.
-
对于 named(…)
部分,您始终需要添加一对 value(producer(…), consumer(…))
调用。只设置 DSL 属性(如只设置 value(producer(…))
或只设置 file(…)
)不起作用。有关更多信息,请查看此 issue。
For the named(…)
section you always have to add a pair of
value(producer(…), consumer(…))
calls. Just setting DSL properties such
as just value(producer(…))
or just file(…)
will not work.
Check this issue for more information.
从上例中的契约来看,生成的测试和存根如下所示:
From the contract in the preceding example, the generated test and stub look as follows:
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "multipart/form-data;boundary=AaB03x")
.param("formParameter", "\"formParameterValue\"")
.param("someBooleanParameter", "true")
.multiPart("file", "filename.csv", "file content".getBytes());
// when:
ResponseOptions response = given().spec(request)
.put("/multipart");
// then:
assertThat(response.statusCode()).isEqualTo(200);
Unresolved directive in _dsl-request.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy[]
HTTP Response
HTTP Response
响应必须包含一个 HTTP 状态代码,并且可以包含其他信息。以下代码显示一个示例:
The response must contain an HTTP status code and may contain other information. The following code shows an example:
Unresolved directive in _dsl-response.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[]
Unresolved directive in _dsl-response.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
...
Unresolved directive in _dsl-response.adoc - include::{verifier_root_path}/src/test/resources/yml/contract.yml[]
Unresolved directive in _dsl-response.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[]
Unresolved directive in _dsl-response.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[]
除了状态之外,响应可能包含标头、Cookie 和正文,以与请求中指定的方式相同(请参阅 HTTP Request)。
Besides status, the response may contain headers, cookies, and a body, which are specified the same way as in the request (see HTTP Request).
在 Groovy DSL 中,你可以引用 |
In the Groovy DSL, you can reference the |
XML Support for HTTP
XML Support for HTTP
对于 HTTP 合同,我们还支持在请求和响应正文中使用 XML。XML 正文必须在 body
元素中作为 String
或 GString
传递。此外,可以为请求和响应提供正文匹配器。在 jsonPath(…)
方法处,应使用 org.springframework.cloud.contract.spec.internal.BodyMatchers.xPath
方法,以第一个参数的形式提供所需 xPath
,并以第二个参数的形式提供适当的 MatchingType
。除 byType()
外的所有正文匹配器都受支持。
For HTTP contracts, we also support using XML in the request and response body.
The XML body has to be passed within the body
element
as a String
or GString
. Also, body matchers can be provided for
both the request and the response. In place of the jsonPath(…)
method, the org.springframework.cloud.contract.spec.internal.BodyMatchers.xPath
method should be used, with the desired xPath
provided as the first argument
and the appropriate MatchingType
as the second argument. All the body matchers apart from byType()
are supported.
以下示例显示了一个在响应正文中包含 XML 的 Groovy DSL 合同:
The following example shows a Groovy DSL contract with XML in the response body:
Unresolved directive in _dsl-xml.adoc - include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy[]
Unresolved directive in _dsl-xml.adoc - include::{verifier_root_path}/src/test/resources/yml/contract_rest_xml.yml[]
Unresolved directive in _dsl-xml.adoc - include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_xml.java[]
Unresolved directive in _dsl-xml.adoc - include::{verifier_root_path}/src/test/resources/kotlin/contract_xml.kts[]
以下示例显示了一个为响应正文中的 XML 自动生成的测试:
The following example shows an automatically generated test for XML in the response body:
@Test
public void validate_xmlMatches() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/xml");
// when:
ResponseOptions response = given().spec(request).get("/get");
// then:
assertThat(response.statusCode()).isEqualTo(200);
// and:
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document parsedXml = documentBuilder.parse(new InputSource(
new StringReader(response.getBody().asString())));
// and:
assertThat(valueFromXPath(parsedXml, "/test/list/elem/text()")).isEqualTo("abc");
assertThat(valueFromXPath(parsedXml,"/test/list/elem[2]/text()")).isEqualTo("def");
assertThat(valueFromXPath(parsedXml, "/test/duck/text()")).matches("[0-9]\{3}");
assertThat(nodeFromXPath(parsedXml, "/test/duck/xxx")).isNull();
assertThat(valueFromXPath(parsedXml, "/test/alpha/text()")).matches("[\\p\{L}]*");
assertThat(valueFromXPath(parsedXml, "/test/*/complex/text()")).isEqualTo("foo");
assertThat(valueFromXPath(parsedXml, "/test/duck/@type")).isEqualTo("xtype");
}
XML Support for Namespaces
支持命名空间 XML。但是,用于选择命名空间内容的任何 XPath 表达式都必须更新。
Namespaced XML is supported. However, any XPath expresssions used to select namespaced content must be updated.
考虑以下显式命名空间 XML 文档:
Consider the following explicitly namespaced XML document:
<ns1:customer xmlns:ns1="http://demo.com/customer">
<email>customer@test.com</email>
</ns1:customer>
用于选择电子邮件地址的 XPath 表达式为:/ns1:customer/email/text()
。
The XPath expression to select the email address is: /ns1:customer/email/text()
.
请当心,因为不合格的表达式 (/customer/email/text()
) 导致 ""
。
Beware as the unqualified expression (/customer/email/text()
) results in ""
.
对于使用不合格命名空间的内容,该表达式更加详细。考虑以下使用不合格命名空间的 XML 文档:
For content that uses an unqualified namespace, the expression is more verbose. Consider the following XML document that uses an unqualified namespace:
<customer xmlns="http://demo.com/customer">
<email>customer@test.com</email>
</customer>
用于选择电子邮件地址的 XPath 表达式为
The XPath expression to select the email address is
*/[local-name()='customer' and namespace-uri()='http://demo.com/customer']/*[local-name()='email']/text()
请注意,因为不合格的表达式 (/customer/email/text()
或 */[local-name()='customer' and namespace-uri()='http://demo.com/customer']/email/text()
) 会导致 ""
。即使是子元素也必须使用 local-name
语法引用。
Beware, as the unqualified expressions (/customer/email/text()
or */[local-name()='customer' and namespace-uri()='http://demo.com/customer']/email/text()
)
result in ""
. Even the child elements have to be referenced with the local-name
syntax.
General Namespaced Node Expression Syntax
-
Node using qualified namespace:
/<node-name>
-
Node using and defining an unqualified namespace:
/*[local-name=()='<node-name>' and namespace-uri=()='<namespace-uri>']
在某些情况下,您可以忽略 |
In some cases, you can omit the |
-
Node using an unqualified namespace (one of its ancestor’s defines the xmlns attribute):
/*[local-name=()='<node-name>']
Asynchronous Support
Asynchronous Support
如果你在服务器端使用异步通信(你的控制器返回 Callable
、DeferredResult
等),则必须在合同中在 response
部分提供一个 async()
方法。以下代码显示了一个示例:
If you use asynchronous communication on the server side (your controllers are
returning Callable
, DeferredResult
, and so on), then, inside your contract, you must
provide an async()
method in the response
section. The following code shows an example:
org.springframework.cloud.contract.spec.Contract.make {
request {
method GET()
url '/get'
}
response {
status OK()
body 'Passed'
async()
}
}
response:
async: true
class contract implements Supplier<Collection<Contract>> {
@Override
public Collection<Contract> get() {
return Collections.singletonList(Contract.make(c -> {
c.request(r -> {
// ...
});
c.response(r -> {
r.async();
// ...
});
}));
}
}
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
contract {
request {
// ...
}
response {
async = true
// ...
}
}
你还可以使用 fixedDelayMilliseconds
方法或属性为你的存根添加延迟。以下示例演示如何执行此操作:
You can also use the fixedDelayMilliseconds
method or property to add delay to your stubs.
The following example shows how to do so:
org.springframework.cloud.contract.spec.Contract.make {
request {
method GET()
url '/get'
}
response {
status 200
body 'Passed'
fixedDelayMilliseconds 1000
}
}
response:
fixedDelayMilliseconds: 1000
class contract implements Supplier<Collection<Contract>> {
@Override
public Collection<Contract> get() {
return Collections.singletonList(Contract.make(c -> {
c.request(r -> {
// ...
});
c.response(r -> {
r.fixedDelayMilliseconds(1000);
// ...
});
}));
}
}
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
contract {
request {
// ...
}
response {
delay = fixedMilliseconds(1000)
// ...
}
}