常用頂層元素

以下章節描述最常用的頂層元素

描述

您可以為您的契約新增 description。描述是任意文字。以下程式碼顯示範例

Groovy
			org.springframework.cloud.contract.spec.Contract.make {
				description('''
given:
	An input
when:
	Sth happens
then:
	Output
''')
			}
YAML
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)
Java
Contract.make(c -> {
	c.description("Some description");
}));
Kotlin
contract {
	description = """
given:
	An input
when:
	Sth happens
then:
	Output
"""
}

名稱

您可以為您的契約提供名稱。假設您提供以下名稱:should register a user。如果您這樣做,自動產生的測試名稱將為 validate_should_register_a_user。此外,WireMock Stub 中的 Stub 名稱將為 should_register_a_user.json

您必須確保名稱不包含任何會導致產生的測試無法編譯的字元。此外,請記住,如果您為多個契約提供相同的名稱,您的自動產生測試將無法編譯,且您產生的 Stub 將互相覆寫。

以下範例顯示如何將名稱新增至契約

Groovy
org.springframework.cloud.contract.spec.Contract.make {
	name("some_special_name")
}
YAML
name: some name
Java
Contract.make(c -> {
	c.name("some name");
}));
Kotlin
contract {
	name = "some_special_name"
}

忽略契約

如果您想要忽略契約,您可以設定外掛程式組態中忽略契約的值,或在契約本身上設定 ignored 屬性。以下範例顯示如何執行此操作

Groovy
org.springframework.cloud.contract.spec.Contract.make {
	ignored()
}
YAML
ignored: true
Java
Contract.make(c -> {
	c.ignored();
}));
Kotlin
contract {
	ignored = true
}

進行中的契約

進行中的契約不會在生產者端產生測試,但允許產生 Stub。

請謹慎使用此功能,因為它可能會導致誤報,因為您產生 Stub 供消費者使用,但實際上尚未實作。

如果您想要設定進行中的契約,以下範例顯示如何執行此操作

Groovy
org.springframework.cloud.contract.spec.Contract.make {
	inProgress()
}
YAML
inProgress: true
Java
Contract.make(c -> {
	c.inProgress();
}));
Kotlin
contract {
	inProgress = true
}

您可以設定 failOnInProgress Spring Cloud Contract 外掛程式屬性的值,以確保當您的來源中至少有一個進行中的契約時,您的建置會中斷。

從檔案傳遞值

從版本 1.2.0 開始,您可以從檔案傳遞值。假設您的專案中有以下資源

└── src
    └── test
        └── resources
            └── contracts
                ├── readFromFile.groovy
                ├── request.json
                └── response.json

進一步假設您的契約如下

Groovy
/*
 * 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
		}
	}
}

進一步假設 JSON 檔案如下

request.json
{
  "status": "REQUEST"
}
response.json
{
  "status": "RESPONSE"
}

當進行測試或 Stub 產生時,request.jsonresponse.json 檔案的內容會傳遞至要求或回應的主體。檔案名稱必須是相對於契約所在資料夾位置的檔案。

如果您需要以二進位格式傳遞檔案的內容,您可以使用程式碼 DSL 中的 fileAsBytes 方法或 YAML 中的 bodyFromFileAsBytes 欄位。

以下範例顯示如何傳遞二進位檔案的內容

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
		}
	}
}
當您想要處理 HTTP 和訊息傳遞的二進位酬載時,應使用此方法。

Metadata

您可以將 metadata 新增至您的契約。透過 metadata,您可以將組態傳遞至擴充功能。以下您可以找到使用 wiremock 金鑰的範例。其值是一個地圖,其金鑰為 stubMapping,值為 WireMock 的 StubMapping 物件。Spring Cloud Contract 能夠使用您的自訂程式碼修補您產生的 Stub 對應的部分。您可能想要這樣做,以便新增 Webhook、自訂延遲或與第三方 WireMock 擴充功能整合。

groovy
Contract.make {
	request {
		method GET()
		url '/drunks'
	}
	response {
		status OK()
		body([
			count: 100
		])
		headers {
			contentType("application/json")
		}
	}
	metadata([
		wiremock: [
			stubMapping: '''\
				{
					"response" : {
						"fixedDelayMilliseconds": 2000
					}
				}
			'''
			]
	])
}
yml
name: "should count all frauds"
request:
  method: GET
  url: /yamlfrauds
response:
  status: 200
  body:
    count: 200
  headers:
    Content-Type: application/json
metadata:
  wiremock:
    stubMapping: >
      {
        "response" : {
          "fixedDelayMilliseconds": 2000
        }
      }
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
  }
}"""))
}

在以下章節中,您可以找到支援的 metadata 條目的範例。

HTTP 契約

Spring Cloud Contract 可讓您驗證使用 REST 或 HTTP 作為通訊方式的應用程式。Spring Cloud Contract 驗證對於符合契約 request 部分條件的要求,伺服器提供的回應是否符合契約的 response 部分。隨後,契約用於產生 WireMock Stub,對於任何符合所提供條件的要求,都會提供適當的回應。