在生產者端使用契約進行消費者驅動契約 (CDC) 的分步指南

考慮一個欺詐檢測和貸款發放過程的示例。業務場景是:我們想向人們發放貸款,但又不希望他們從我們這裡騙取錢財。我們系統的當前實現是向所有人發放貸款。

假設貸款發放欺詐檢測伺服器的客戶端。在當前衝刺中,我們必須開發一個新功能:如果客戶想借的錢太多,我們就將該客戶標記為欺詐。

技術說明

  • 欺詐檢測的artifact-idhttp-server

  • 貸款發放的artifact-idhttp-client

  • 兩者都有一個group-id,即com.example

  • 為了這個例子,存根儲存是 Nexus/Artifactory。

社會說明

  • 客戶端和伺服器開發團隊都需要直接溝通,並在過程中討論變更。

  • CDC 核心在於溝通。

伺服器端程式碼可在 Spring Cloud Contract Samples 倉庫的 samples/standalone/dsl/http-server 路徑下找到,客戶端程式碼可在 Spring Cloud Contract 倉庫的 samples/standalone/dsl/http-client 路徑下找到。

在這種情況下,生產者擁有契約。實際上,所有契約都在生產者的倉庫中。

技術說明

重要提示:所有程式碼都可在 Spring Cloud Contract Samples 倉庫中找到。

為簡潔起見,我們使用以下縮寫

  • 貸款發放 (LI):HTTP 客戶端

  • 欺詐檢測 (FD):HTTP 伺服器

  • SCC:Spring Cloud Contract

消費者端(貸款發放)

作為貸款發放服務(欺詐檢測伺服器的消費者)的開發者,您可以執行以下步驟

  1. 透過為您的功能編寫測試來開始 TDD。

  2. 編寫缺失的實現。

  3. 在本地克隆欺詐檢測服務倉庫。

  4. 在欺詐檢測服務的倉庫中本地定義契約。

  5. 新增 Spring Cloud Contract (SCC) 外掛。

  6. 執行整合測試。

  7. 提交拉取請求。

  8. 建立初始實現。

  9. 接管拉取請求。

  10. 編寫缺失的實現。

  11. 部署您的應用程式。

  12. 線上工作。

我們從貸款發放流程開始,以下 UML 圖顯示了該流程

getting-started-cdc-client

透過為您的功能編寫測試來開始 TDD

以下清單顯示了我們可能用來檢查貸款金額是否過大的測試

假設您已經編寫了新功能的測試。如果收到的貸款申請金額過大,系統應該拒絕該貸款申請並附帶一些描述。

編寫缺失的實現

在某個時刻,您需要向欺詐檢測服務傳送請求。假設您需要傳送包含客戶 ID 和客戶想要借款金額的請求。您想透過 PUT 方法將其傳送到 /fraudcheck URL。為此,您可以使用類似於以下程式碼的程式碼

為簡單起見,欺詐檢測服務的埠設定為 8080,應用程式執行在 8090

如果此時您啟動測試,它會中斷,因為目前沒有服務在埠 8080 上執行。

在本地克隆欺詐檢測服務倉庫

您可以從嘗試伺服器端契約開始。為此,您必須首先透過執行以下命令來克隆它

$ git clone https://your-git-server.com/server-side.git local-http-server-repo

在欺詐檢測服務的倉庫中本地定義契約

作為消費者,您需要明確定義您想要實現的目標。您需要闡明您的期望。為此,請編寫以下契約

將契約放置在 src/test/resources/contracts/fraud 資料夾中。fraud 資料夾很重要,因為生產者的測試基類名稱引用了該資料夾。

以下示例顯示了我們的契約,包括 Groovy 和 YAML 格式

YML 契約非常直截了當。然而,當您檢視使用靜態型別 Groovy DSL 編寫的契約時,您可能會想 value(client(…​), server(…​)) 部分是什麼。透過使用這種表示法,Spring Cloud Contract 允許您定義 JSON 塊、URL 或其他動態結構的一部分。在識別符號或時間戳的情況下,您無需硬編碼值。您希望允許一些不同範圍的值。要啟用值範圍,您可以設定與消費者側這些值匹配的正則表示式。您可以透過對映表示法或帶插值的字串提供正文。我們強烈建議使用對映表示法。

要設定契約,您必須瞭解對映表示法。請參閱 Groovy 關於 JSON 的文件

前面顯示的契約是雙方之間的協議,即

  • 如果傳送 HTTP 請求時包含所有以下內容

    • /fraudcheck 端點的 PUT 方法

    • 一個 JSON 主體,其中 client.id 匹配正則表示式 [0-9]{10}loanAmount 等於 99999

    • Content-Type 標頭,值為 application/vnd.fraud.v1+json

  • 則會向消費者傳送一個 HTTP 響應,該響應

    • 狀態為 200

    • 包含一個 JSON 主體,其中 fraudCheckStatus 欄位的值為 FRAUDrejectionReason 欄位的值為 Amount too high

    • Content-Type 標頭,值為 application/vnd.fraud.v1+json

一旦您準備好在整合測試中實際檢查 API,您需要在本地安裝存根。

新增 Spring Cloud Contract Verifier 外掛

我們可以新增 Maven 或 Gradle 外掛。在此示例中,我們展示如何新增 Maven。首先,我們新增 Spring Cloud Contract BOM,示例如下

接下來,新增 Spring Cloud Contract Verifier Maven 外掛,示例如下

由於外掛已新增,您將獲得 Spring Cloud Contract Verifier 的功能,這些功能根據提供的契約

  • 生成並執行測試

  • 生成並安裝存根

您不想生成測試,因為作為消費者,您只想使用存根。您需要跳過測試生成和呼叫。為此,請執行以下命令

$ cd local-http-server-repo
$ ./mvnw clean install -DskipTests

執行這些命令後,您應該在日誌中看到類似以下內容

[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server ---
[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar
[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom
[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

以下這行非常重要

[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

它確認 http-server 的存根已安裝到本地倉庫。

執行整合測試

為了利用 Spring Cloud Contract Stub Runner 自動下載存根的功能,您必須在您的消費者端專案(貸款申請服務)中執行以下操作

  1. 新增 Spring Cloud Contract BOM,如下所示

  2. 新增 Spring Cloud Contract Stub Runner 的依賴項,如下所示

  3. 使用 @AutoConfigureStubRunner 註解您的測試類。在註解中,為 Stub Runner 提供 group-idartifact-id,以便下載您的協作者的存根。

  4. (可選)因為您正在離線與協作者一起玩,您還可以提供離線工作開關(StubRunnerProperties.StubsMode.LOCAL)。

現在,當您執行測試時,您會在日誌中看到類似以下輸出

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

此輸出意味著 Stub Runner 找到了您的存根,併為您的應用程式啟動了一個伺服器,其 group ID 為 com.example,artifact ID 為 http-server,存根版本為 0.0.1-SNAPSHOT,分類器為 stubs,埠為 8080

提交拉取請求

到目前為止您所做的是一個迭代過程。您可以反覆嘗試契約,在本地安裝它,並在消費者端進行工作,直到契約按您希望的方式執行。

一旦您對結果滿意且測試透過,您就可以向伺服器端釋出拉取請求。目前,消費者端的工作已完成。

生產者端(欺詐檢測伺服器)

作為欺詐檢測伺服器(貸款發放服務的伺服器)的開發者,您可能希望

  • 接管拉取請求

  • 編寫缺失的實現

  • 部署應用程式

以下 UML 圖顯示了欺詐檢測流程

getting-started-cdc-server

接管拉取請求

作為提醒,以下清單顯示了初始實現

然後您可以執行以下命令

$ git checkout -b contract-change-pr master
$ git pull https://your-git-server.com/server-side-fork.git contract-change-pr

您必須新增自動生成的測試所需的依賴項,如下所示

在 Maven 外掛的配置中,您必須傳遞 packageWithBaseClasses 屬性,如下所示

此示例透過設定 packageWithBaseClasses 屬性使用“基於約定”的命名。這樣做意味著最後兩個包組合起來構成基礎測試類的名稱。在我們的例子中,契約位於 src/test/resources/contracts/fraud 下。由於從 contracts 資料夾開始沒有兩個包,因此只選擇一個,即 fraud。新增 Base 字尾並將 fraud 首字母大寫。這將為您提供 FraudBase 測試類名。

所有生成的測試都擴充套件該類。在那裡,您可以設定您的 Spring 上下文或任何必要的東西。在這種情況下,您應該使用 Rest Assured MVC 來啟動伺服器端 FraudDetectionController。以下清單顯示了 FraudBase

現在,如果您執行 ./mvnw clean install,您會得到類似以下的輸出

Results :

Tests in error:
  ContractVerifierTest.validate_shouldMarkClientAsFraud:32 » IllegalState Parsed...

此錯誤發生是因為您有一個新的契約,從中生成了一個測試,並且由於您尚未實現該功能,該測試失敗了。自動生成的測試將類似於以下測試方法

@Test
public void validate_shouldMarkClientAsFraud() throws Exception {
    // given:
        MockMvcRequestSpecification request = given()
                .header("Content-Type", "application/vnd.fraud.v1+json")
                .body("{\"client.id\":\"1234567890\",\"loanAmount\":99999}");

    // when:
        ResponseOptions response = given().spec(request)
                .put("/fraudcheck");

    // then:
        assertThat(response.statusCode()).isEqualTo(200);
        assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*");
    // and:
        DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
        assertThatJson(parsedJson).field("['fraudCheckStatus']").matches("[A-Z]{5}");
        assertThatJson(parsedJson).field("['rejection.reason']").isEqualTo("Amount too high");
}

如果您使用 Groovy DSL,您會看到契約中 value(consumer(…​), producer(…​)) 塊中所有 producer() 部分都被注入到測試中。如果您使用 YAML,同樣適用於 responsematchers 部分。

請注意,在生產者端,您也在進行 TDD。期望以測試的形式表達。此測試向我們自己的應用程式傳送一個請求,其中包含契約中定義的 URL、標頭和正文。它還期望響應中包含精確定義的值。換句話說,您擁有 redgreenrefactor 中的 red 部分。現在是時候將 red 轉換為 green 了。

編寫缺失的實現

由於您知道預期的輸入和輸出,您可以按如下方式編寫缺失的實現

當您再次執行 ./mvnw clean install 時,測試透過。由於 Spring Cloud Contract Verifier 外掛將測試新增到 generated-test-sources,您實際上可以從 IDE 中執行這些測試。

部署您的應用程式

完成工作後,您可以部署更改。為此,您必須首先透過執行以下命令合併分支

$ git checkout master
$ git merge --no-ff contract-change-pr
$ git push origin master

您的 CI 可能會執行類似 ./mvnw clean deploy 的命令,該命令將釋出應用程式和存根工件。

消費者端(貸款發放),最後一步

作為貸款發放服務(欺詐檢測伺服器的消費者)的開發者,您需要

  • 將我們的功能分支合併到 master

  • 切換到線上工作模式

以下 UML 圖顯示了流程的最終狀態

getting-started-cdc-client-final

將分支合併到主分支

以下命令顯示了使用 Git 將分支合併到主分支的一種方式

$ git checkout master
$ git merge --no-ff contract-change-pr

線上工作

現在您可以停用 Spring Cloud Contract Stub Runner 的離線工作,並指出存根倉庫的位置。此時,伺服器端的存根會自動從 Nexus/Artifactory 下載。您可以將 stubsMode 的值設定為 REMOTE。以下程式碼顯示了透過更改屬性實現相同目標的示例

就是這樣。您已經完成了本教程。

© . This site is unofficial and not affiliated with VMware.