英文原文:https://spring.io/projects/spring-cloud-contract
目錄
概述
特性
Spring Boot配置
Server / Producer方面
Client / Consumer方面
快速開始
學習
文檔
示例
概述
Spring Cloud Contract是一個總體項目,其中包含幫助使用者成功實施消費者驅動合同方法的解決方案。目前,Spring Cloud Contract包含Spring Cloud Contract Verifier項目。
Spring Cloud Contract Verifier是一個支援基于JVM的應用程式的消費者驅動合同(CDC)開發的工具。它附帶了用Groovy或YAML編寫的合同定義語言(DSL)。合同定義用于生成以下資源:
- 預設情況下,在對用戶端代碼(用戶端測試)進行內建測試時,WireMock(HTTP Server Stub)将使用JSON存根定義。測試代碼仍然必須手工編寫,測試資料由Spring Cloud Contract Verifier生成。
- 如果你使用消息路由消息路由。我們正在與Spring Integration,Spring Cloud Stream和Apache Camel內建。但是,如果您願意,可以設定自己的內建。
- 驗證測試(預設情況下,在JUnit或Spock中)用于驗證API的伺服器端實作是否符合合同(伺服器測試)。 Spring Cloud Contract Verifier生成完整測試。
Spring Cloud Contract Verifier将TDD提升到軟體架構的水準。
要了解Spring Cloud Contract如何支援其他語言,請檢視此部落格文章。
特性
在嘗試測試與其他服務通信的應用程式時,我們可以執行以下兩項操作之一:
- 部署所有微服務并執行端到端測試
- 模拟單元/內建測試中的其他微服務
兩者都有其優點,但也有很多缺點。讓我們關注後者。
部署所有微服務并執行端到端測試
好處:
- 模拟生産
- 測試服務之間的真實通信
缺點:
- 為了測試一個微服務,我們必須部署6個微服務,幾個資料庫等。
- 将進行測試的環境将被鎖定用于單個測試套件(即,在此期間沒有其他人能夠運作測試)。
- 很長時間跑
- 很晚的回報
- 非常難以調試
在單元/內建測試中模拟其他微服務
好處:
- 非常快速的回報
- 無基礎設施要求
缺點:
- 服務的實作者建立存根,是以他們可能與現實無關
- 你可以通過測試和生産失敗去生産
為了解決上述問題,建立了帶有Stub Runner的Spring Cloud Contract Verifier。他們的主要想法是給你非常快速的回報,而不需要建立整個微服務世界。
Spring Cloud Contract Verifier功能:
- 確定HTTP / Messaging存根(在開發用戶端時使用)正在執行實際的伺服器端實作
- 促進驗收測試驅動開發方法和微服務架構風格
- 提供一種方法來釋出在通信雙方立即可見的合同中的更改
- 生成伺服器端使用的樣闆測試代碼
Spring Boot配置
有關詳細的分步指南,請檢視文檔。 您可以在下面找到簡化版本。
Server / Producer方面
在伺服器(HTTP)/生産者(消息傳遞)方面添加Spring Cloud Contract Verifier Maven / Gradle插件。 我們假設我們項目的組ID是com.example,工件id是http-server。
在配置中傳遞的測試的基類可能看起來像這樣(我們假設我們正在使用[Rest Assured](http://rest-assured.io/)并且我們想要為FraudDetectionController執行CDC 你在寫)
package com.example;
// imports
public class MvcTest {
@Before
public void setup() {
RestAssuredMockMvc.standaloneSetup(new FraudDetectionController());
}
}
在src/test/resources/contracts中添加一個Contract定義。 例如名為shouldMarkClientAsFraud.groovy
org.springframework.cloud.contract.spec.Contract.make {
request {
method 'PUT'
url '/fraudcheck'
body("""
{
"clientId":"1234567890",
"loanAmount":99999
}
""")
headers {
header('Content-Type', 'application/vnd.fraud.v1+json')
}
}
response {
status 200
body("""
{
"fraudCheckStatus": "FRAUD",
"rejectionReason": "Amount too high"
}
""")
headers {
header('Content-Type': 'application/vnd.fraud.v1+json')
}
}
}
如果你必須添加一個插件,将為你生成測試和存根。
Maven
<build>
<plugins>
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
<configuration>
<baseClassForTests>com.example.MvcTest</baseClassForTests>
</configuration>
</plugin>
</plugins>
</build>
Gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootPluginVersion}"
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${springCloudContractVersion}"
}
}
apply plugin: 'spring-boot'
apply plugin: 'spring-cloud-contract'
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${springCloudDependencies}"
}
}
dependencies {
testCompile "org.springframework.cloud:spring-cloud-starter-contract-verifier"
}
contracts {
baseClassForTests = 'com.example.MvcTest'
}
一旦您嘗試從合同建構應用程式,将在/generated-test-sources/contracts下的輸出檔案夾中生成測試。
package org.springframework.cloud.contract.verifier.tests;
// imports
public class ContractVerifierTest extends MvcTest {
@Test
public void validate_shouldMarkClientAsFraud() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/vnd.fraud.v1+json")
.body("{\"clientId\":\"1234567890\",\"loanAmount\":99999}");
// when:
ResponseOptions response = given().spec(request)
.put("/fraudcheck");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).isEqualTo("application/vnd.fraud.v1+json");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field("fraudCheckStatus").isEqualTo("FRAUD");
assertThatJson(parsedJson).field("rejectionReason").isEqualTo("Amount too high");
}
}
一旦您通過并重新運作工件的建構和安裝,Spring Cloud Contract Verifier就會将合同轉換為HTTP伺服器存根定義。 目前我們正在支援WireMock。 存根将出現在stubs/mappings/下的輸出檔案夾中,如下所示:
{
"uuid" : "6c509a40-18f3-498c-a19c-c9f8b56957de",
"request" : {
"url" : "/fraudcheck",
"method" : "PUT",
"headers" : {
"Content-Type" : {
"equalTo" : "application/vnd.fraud.v1+json"
}
},
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.loanAmount == 99999)]"
}, {
"matchesJsonPath" : "$[?(@.clientId == '1234567890')]"
} ]
},
"response" : {
"status" : 200,
"body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}",
"headers" : {
"Content-Type" : "application/vnd.fraud.v1+json"
}
}
}
CDC(消費者驅動合同)背後的想法是分享通信雙方之間的合同。 Gradle和Maven插件通過使用存根分類器生成帶有存根和合約定義的jar來幫助您實作這一點。 隻需将其上傳到某個中央存儲庫,其他人可以将其重新用于內建測試。
Client / Consumer方面
在用戶端(HTTP)/使用者(消息傳遞)方面,它足以為正确的Spring Cloud Contract Stub Runner實作提供依賴性。 在這種情況下,因為我們的示例包含與WireMock的HTTP通信作為HTTP Server Stub。 我們将選擇以下依賴項:
Maven
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootPluginVersion}"
}
}
apply plugin: 'spring-boot'
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${springCloudDependencies}"
}
}
dependencies {
testCompile "org.springframework.cloud:spring-cloud-starter-contract-stub-runner"
}
最後一步是在測試中設定Stub Runner以自動下載下傳所需的存根。 要實作這一點,您必須傳遞@AutoConfigureStubRunner注釋。 該注釋具有一組您可以設定的屬性。 如果您不喜歡這種方法,您也可以在測試屬性中設定這些值。
對于Spring Cloud Contract 1.2.x
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(ids = {"com.example:http-server:+:stubs:8080"}, workOffline = true)
public class LoanApplicationServiceTests {
對于從2.0.x開始的Spring Cloud Contract
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(ids = {"com.example:http-server:+:stubs:8080"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class LoanApplicationServiceTests {
這樣,具有組ID com.example的工件,工件id http-server,在最新版本中,具有存根分類器将在端口8080處注冊。由于傳遞了workOffline标志,是以将不從遠端存儲庫下載下傳存根 - 它 将在當地的Maven回購中搜尋。 一旦您的測試上下文啟動,執行以下代碼将不會導緻404,因為Spring Cloud Contract Stub Runner将自動啟動測試中的WireMock伺服器并使用從伺服器端生成的存根來提供它。
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/vnd.fraud.v1+json");
String response = restTemplate.exchange("http://localhost:8080/fraudcheck", HttpMethod.PUT,
new HttpEntity<>("{\"clientId\":\"1234567890\",\"loanAmount\":99999}", httpHeaders),
String.class);
assertThat(response).isEqualTo("{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}");
快速開始
使用Spring Initializr引導您的應用程式。
學習
文檔
每個Spring項目都有自己的; 它詳細解釋了如何使用項目功能以及使用它們可以實作的功能。
2.1.0 RC3 PRE CURRENT | Reference Doc. | API Doc. |
2.0.3 SNAPSHOT CURRENT | Reference Doc. | API Doc. |
2.0.2 CURRENT GA | Reference Doc. | API Doc. |
1.2.6 SNAPSHOT CURRENT | Reference Doc. | API Doc. |
1.2.5 CURRENT GA | Reference Doc. | API Doc. |
1.1.6 SNAPSHOT | Reference Doc. | API Doc. |
1.1.5 GA | Reference Doc. | API Doc. |
1.0.5 SNAPSHOT | Reference Doc. | API Doc. |
1.0.4 GA | Reference Doc. | API Doc. |
示例
嘗試一些例子:
- Spring Cloud Contract Samples (Edgware) 使用Boot 1.5和Edgware版本列的Spring Cloud Contract樣本
- Spring Cloud Contract Samples (Finchley) 使用Boot 2.x和Finchley釋出清單進行Spring Cloud Contract的示例
- Spring Cloud Contract workshops 與Spring Cloud合同的研讨會
- Spring Cloud Contract with NodeJS 您可以在此處閱讀有關Polyglot方法的更多資訊https://spring.io/blog/2018/02/13/spring-cloud-contract-in-a-polyglot-world