对于最新的稳定版本,请使用 spring-cloud-contract 4.2.0! |
常见顶级元素
描述
您可以添加description
添加到您的合同中。描述是任意文本。这
下面的代码显示了一个示例:
org.springframework.cloud.contract.spec.Contract.make {
description('''
given:
An input
when:
Sth happens
then:
Output
''')
}
description: Some description
name: some name
priority: 8
ignored: true
request:
url: /foo
queryParameters:
a: b
b: c
method: PUT
headers:
foo: bar
fooReq: baz
body:
foo: bar
matchers:
body:
- path: $.foo
type: by_regex
value: bar
headers:
- key: foo
regex: bar
response:
status: 200
headers:
foo2: bar
foo3: foo33
fooRes: baz
body:
foo2: bar
foo3: baz
nullValue: null
matchers:
body:
- path: $.foo2
type: by_regex
value: bar
- path: $.foo3
type: by_command
value: executeMe($it)
- path: $.nullValue
type: by_null
value: null
headers:
- key: foo2
regex: bar
- key: foo3
command: andMeToo($it)
Contract.make(c -> {
c.description("Some description");
}));
contract {
description = """
given:
An input
when:
Sth happens
then:
Output
"""
}
名字
您可以为合同提供名称。假设您提供以下名称:should register a user
.如果这样做,则自动生成的测试的名称为validate_should_register_a_user
.此外,WireMock 存根中的存根名称为should_register_a_user.json
.
您必须确保名称不包含任何使 生成的测试未编译。另外,请记住,如果您为 多个 Contract,则自动生成的测试无法编译,并且生成的存根 相互覆盖。 |
以下示例演示如何向协定添加名称:
org.springframework.cloud.contract.spec.Contract.make {
name("some_special_name")
}
name: some name
Contract.make(c -> {
c.name("some name");
}));
contract {
name = "some_special_name"
}
忽略合同
如果要忽略合约,可以在
plugin 配置或设置ignored
property 的 intent 属性。以下内容
示例展示了如何做到这一点:
org.springframework.cloud.contract.spec.Contract.make {
ignored()
}
ignored: true
Contract.make(c -> {
c.ignored();
}));
contract {
ignored = true
}
正在进行的合同
正在进行的合同不会在生产者端生成测试,但允许生成存根。
请谨慎使用此功能,因为它可能会导致误报,因为您会生成存根供使用者使用,而实际上没有实施。 |
如果要设置正在进行的合同,请执行以下作 示例展示了如何做到这一点:
org.springframework.cloud.contract.spec.Contract.make {
inProgress()
}
inProgress: true
Contract.make(c -> {
c.inProgress();
}));
contract {
inProgress = true
}
您可以设置failOnInProgress
Spring Cloud Contract 插件属性,以确保当源中至少有一个正在进行的 Contract 时,您的构建会中断。
从文件传递值
从 version 开始1.2.0
中,您可以从文件中传递值。假设您拥有
项目中的以下资源:
└── src
└── test
└── resources
└── contracts
├── readFromFile.groovy
├── request.json
└── response.json
进一步假设您的 Contract 如下:
/*
* Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.springframework.cloud.contract.spec.Contract
Contract.make {
request {
method('PUT')
headers {
contentType(applicationJson())
}
body(file("request.json"))
url("/1")
}
response {
status OK()
body(file("response.json"))
headers {
contentType(applicationJson())
}
}
}
YAML
request:
method: GET
url: /foo
bodyFromFile: request.json
response:
status: 200
bodyFromFile: response.json
Java
import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;
import org.springframework.cloud.contract.spec.Contract;
class contract_rest_from_file implements Supplier<Collection<Contract>> {
@Override
public Collection<Contract> get() {
return Collections.singletonList(Contract.make(c -> {
c.request(r -> {
r.url("/foo");
r.method(r.GET());
r.body(r.file("request.json"));
});
c.response(r -> {
r.status(r.OK());
r.body(r.file("response.json"));
});
}));
}
}
Kotlin
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
contract {
request {
url = url("/1")
method = PUT
headers {
contentType = APPLICATION_JSON
}
body = bodyFromFile("request.json")
}
response {
status = OK
body = bodyFromFile("response.json")
headers {
contentType = APPLICATION_JSON
}
}
}
Further assume that the JSON files are as follows:
request.json
{
"status": "REQUEST"
}
response.json
{
"status": "RESPONSE"
}
When test or stub generation takes place, the contents of the request.json
and response.json
files are passed to the body
of a request or a response. The name of the file needs to be a file in a location
relative to the folder in which the contract resides.
If you need to pass the contents of a file in binary form,
you can use the fileAsBytes
method in the coded DSL or a bodyFromFileAsBytes
field in YAML.
The following example shows how to pass the contents of binary files:
Groovy
import org.springframework.cloud.contract.spec.Contract
Contract.make {
request {
url("/1")
method(PUT())
headers {
contentType(applicationOctetStream())
}
body(fileAsBytes("request.pdf"))
}
response {
status 200
body(fileAsBytes("response.pdf"))
headers {
contentType(applicationOctetStream())
}
}
}
YAML
request:
url: /1
method: PUT
headers:
Content-Type: application/octet-stream
bodyFromFileAsBytes: request.pdf
response:
status: 200
bodyFromFileAsBytes: response.pdf
headers:
Content-Type: application/octet-stream
Java
import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;
import org.springframework.cloud.contract.spec.Contract;
class contract_rest_from_pdf implements Supplier<Collection<Contract>> {
@Override
public Collection<Contract> get() {
return Collections.singletonList(Contract.make(c -> {
c.request(r -> {
r.url("/1");
r.method(r.PUT());
r.body(r.fileAsBytes("request.pdf"));
r.headers(h -> {
h.contentType(h.applicationOctetStream());
});
});
c.response(r -> {
r.status(r.OK());
r.body(r.fileAsBytes("response.pdf"));
r.headers(h -> {
h.contentType(h.applicationOctetStream());
});
});
}));
}
}
Kotlin
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
contract {
request {
url = url("/1")
method = PUT
headers {
contentType = APPLICATION_OCTET_STREAM
}
body = bodyFromFileAsBytes("contracts/request.pdf")
}
response {
status = OK
body = bodyFromFileAsBytes("contracts/response.pdf")
headers {
contentType = APPLICATION_OCTET_STREAM
}
}
}
You should use this approach whenever you want to work with binary payloads,
both for HTTP and messaging.
Metadata
You can add metadata
to your contract. Via the metadata you can pass in configuration to extensions. Below you can find
an example of using the wiremock
key. Its value is a map whose key is stubMapping
and value being WireMock’s StubMapping
object. Spring Cloud Contract is able to
patch parts of your generated stub mapping with your custom code. You may want to do that in order to add webhooks, custom
delays or integrate with third party WireMock extensions.
java
Contract.make(c -> {
c.metadata(MetadataUtil.map()
.entry("wiremock", ContractVerifierUtil.map()
.entry("stubMapping", "{ \"response\" : { \"fixedDelayMilliseconds\" : 2000 } }")));
}));
kotlin
contract {
metadata("wiremock" to ("stubmapping" to """
{
"response" : {
"fixedDelayMilliseconds": 2000
}
}"""))
}
In the following sections you can find examples of the supported metadata entries.
Contracts for HTTP
Spring Cloud Contract lets you verify applications that use REST or HTTP as a
means of communication. Spring Cloud Contract verifies that, for a request that matches the
criteria from the request
part of the contract, the server provides a response that is in
keeping with the response
part of the contract. Subsequently, the contracts are used to
generate WireMock stubs that, for any request matching the provided criteria, provide a
suitable response.