天天看點

Spring系列學習之Spring Cloud Contract測試消息傳遞概述學習示例

英文原文: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