SpringCloud 消費者方(發(fā)放貸款)

2023-12-13 09:50 更新

作為貸款發(fā)行服務的開發(fā)人員(欺詐檢測服務器的使用者),您可以執(zhí)行以下步驟:

  1. 通過為您的功能編寫測試來開始進行TDD。
  2. 編寫缺少的實現(xiàn)。
  3. 在本地克隆欺詐檢測服務存儲庫。
  4. 在欺詐檢測服務的倉庫中本地定義合同。
  5. 添加Spring Cloud Contract驗證程序插件。
  6. 運行集成測試。
  7. 提出拉取請求。
  8. 創(chuàng)建一個初始實現(xiàn)。
  9. 接管請求請求。
  10. 編寫缺少的實現(xiàn)。
  11. 部署您的應用程序。
  12. 在線工作。

通過為您的功能編寫測試來開始進行TDD。

@Test
public void shouldBeRejectedDueToAbnormalLoanAmount() {
	// given:
	LoanApplication application = new LoanApplication(new Client("1234567890"),
			99999);
	// when:
	LoanApplicationResult loanApplication = service.loanApplication(application);
	// then:
	assertThat(loanApplication.getLoanApplicationStatus())
			.isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED);
	assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high");
}

假設您已經編寫了新功能的測試。如果收到大量貸款申請,則系統(tǒng)應拒絕該貸款申請并提供一些說明。

編寫缺少的實現(xiàn)。

在某個時間點,您需要向欺詐檢測服務發(fā)送請求。假設您需要發(fā)送包含客戶ID和客戶希望借入的金額的請求。您想通過PUT方法將其發(fā)送到/fraudcheck網址。

ResponseEntity<FraudServiceResponse> response = restTemplate.exchange(
		"http://localhost:" + port + "/fraudcheck", HttpMethod.PUT,
		new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class);

為簡單起見,欺詐檢測服務的端口設置為8080,應用程序在8090上運行。

如果此時開始測試,則會中斷測試,因為當前沒有服務在端口8080上運行。

在本地克隆欺詐檢測服務存儲庫。

您可以從服務器端合同開始。為此,您必須首先克隆它。

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

在欺詐檢測服務的倉庫中本地定義合同。

作為消費者,您需要定義要實現(xiàn)的目標。您需要制定自己的期望。為此,請編寫以下合同:

 將合同放在src/test/resources/contracts/fraud文件夾下。fraud文件夾很重要,因為生產者的測試基類名稱引用了該文件夾。

Groovy DSL。 

/*
 * Copyright 2013-2019 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.
 */

package contracts

org.springframework.cloud.contract.spec.Contract.make {
	request { // (1)
		method 'PUT' // (2)
		url '/fraudcheck' // (3)
		body([ // (4)
			   "client.id": $(regex('[0-9]{10}')),
			   loanAmount : 99999
		])
		headers { // (5)
			contentType('application/json')
		}
	}
	response { // (6)
		status OK() // (7)
		body([ // (8)
			   fraudCheckStatus  : "FRAUD",
			   "rejection.reason": "Amount too high"
		])
		headers { // (9)
			contentType('application/json')
		}
	}
}

/*
From the Consumer perspective, when shooting a request in the integration test:

(1) - If the consumer sends a request
(2) - With the "PUT" method
(3) - to the URL "/fraudcheck"
(4) - with the JSON body that
 * has a field `client.id` that matches a regular expression `[0-9]{10}`
 * has a field `loanAmount` that is equal to `99999`
(5) - with header `Content-Type` equal to `application/json`
(6) - then the response will be sent with
(7) - status equal `200`
(8) - and JSON body equal to
 { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
(9) - with header `Content-Type` equal to `application/json`

From the Producer perspective, in the autogenerated producer-side test:

(1) - A request will be sent to the producer
(2) - With the "PUT" method
(3) - to the URL "/fraudcheck"
(4) - with the JSON body that
 * has a field `client.id` that will have a generated value that matches a regular expression `[0-9]{10}`
 * has a field `loanAmount` that is equal to `99999`
(5) - with header `Content-Type` equal to `application/json`
(6) - then the test will assert if the response has been sent with
(7) - status equal `200`
(8) - and JSON body equal to
 { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
(9) - with header `Content-Type` matching `application/json.*`
 */

YAML。 

request: # (1)
  method: PUT # (2)
  url: /fraudcheck # (3)
  body: # (4)
    "client.id": 1234567890
    loanAmount: 99999
  headers: # (5)
    Content-Type: application/json
  matchers:
    body:
      - path: $.['client.id'] # (6)
        type: by_regex
        value: "[0-9]{10}"
response: # (7)
  status: 200 # (8)
  body:  # (9)
    fraudCheckStatus: "FRAUD"
    "rejection.reason": "Amount too high"
  headers: # (10)
    Content-Type: application/json;charset=UTF-8


#From the Consumer perspective, when shooting a request in the integration test:
#
#(1) - If the consumer sends a request
#(2) - With the "PUT" method
#(3) - to the URL "/fraudcheck"
#(4) - with the JSON body that
# * has a field `client.id`
# * has a field `loanAmount` that is equal to `99999`
#(5) - with header `Content-Type` equal to `application/json`
#(6) - and a `client.id` json entry matches the regular expression `[0-9]{10}`
#(7) - then the response will be sent with
#(8) - status equal `200`
#(9) - and JSON body equal to
# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
#(10) - with header `Content-Type` equal to `application/json`
#
#From the Producer perspective, in the autogenerated producer-side test:
#
#(1) - A request will be sent to the producer
#(2) - With the "PUT" method
#(3) - to the URL "/fraudcheck"
#(4) - with the JSON body that
# * has a field `client.id` `1234567890`
# * has a field `loanAmount` that is equal to `99999`
#(5) - with header `Content-Type` equal to `application/json`
#(7) - then the test will assert if the response has been sent with
#(8) - status equal `200`
#(9) - and JSON body equal to
# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
#(10) - with header `Content-Type` equal to `application/json;charset=UTF-8`

YML合同很簡單。但是,當您查看使用靜態(tài)類型的Groovy DSL編寫的合同時-您可能會懷疑value(client(…?), server(…?))部分是什么。通過使用此表示法,Spring Cloud Contract使您可以定義JSON塊,URL等動態(tài)的部分。如果是標識符或時間戳,則無需對值進行硬編碼。您要允許一些不同的值范圍。要啟用值范圍,可以為使用者方設置與這些值匹配的正則表達式。您可以通過地圖符號或帶插值的字符串來提供主體。有關更多信息,請參見Contract DSL部分。我們強烈建議您使用地圖符號!

 您必須了解地圖符號才能設置合同。請閱讀有關JSON Groovy文檔。

前面顯示的合同是雙方之間的協(xié)議,其中:

  • 如果HTTP請求與所有

    • /fraudcheck端點上的PUT方法,
    • 一個具有client.id且與正則表達式[0-9]{10}loanAmount等于99999匹配的JSON正文,
    • 和值為application/vnd.fraud.v1+jsonContent-Type標頭,
  • 然后將HTTP響應發(fā)送給使用者

    • 狀態(tài)為200,
    • 包含JSON正文,其fraudCheckStatus字段包含值FRAUD,而rejectionReason字段包含值Amount too high,
    • 還有一個Content-Type標頭,其值為application/vnd.fraud.v1+json。

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

添加Spring Cloud Contract驗證程序插件。

我們可以添加Maven或Gradle插件。在此示例中,您將了解如何添加Maven。首先,添加Spring Cloud Contract BOM。

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud-release.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

接下來,添加Spring Cloud Contract Verifier Maven插件

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<version>${spring-cloud-contract.version}</version>
	<extensions>true</extensions>
	<configuration>
		<packageWithBaseClasses>com.example.fraud</packageWithBaseClasses>
		<convertToYaml>true</convertToYaml>
	</configuration>
</plugin>

自從添加了插件以來,您將獲得Spring Cloud Contract Verifier功能,這些功能來自提供的合同:

  • 生成并運行測試
  • 制作并安裝存根

您不想生成測試,因為作為消費者,您只想玩存根。您需要跳過測試的生成和執(zhí)行。執(zhí)行時:

$ 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功能中受益,您必須在用戶端項目(Loan Application service)中執(zhí)行以下操作:

添加Spring Cloud Contract BOM:

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud-release-train.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

將依賴項添加到Spring Cloud Contract Stub Runner

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
	<scope>test</scope>
</dependency>

@AutoConfigureStubRunner注釋測試類。在注釋中,為Stub Runner提供group-idartifact-id,以下載合作者的存根。(可選步驟)由于您是與離線協(xié)作者一起玩,因此您還可以提供離線工作切換(StubRunnerProperties.StubsMode.LOCAL)。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {
		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class LoanApplicationServiceTests {

現(xiàn)在,當您運行測試時,您將看到類似以下的內容:

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找到了您的存根,并為您的應用啟動了服務器,其組ID為com.example,工件ID為??http-server,存根的版本為0.0.1-SNAPSHOT,且分類器為stubs端口8080。

提出拉取請求。

到目前為止,您所做的是一個迭代過程。您可以試用合同,將其安裝在本地,然后在用戶端工作,直到合同按您的意愿運行。

對結果滿意并通過測試后,將拉取請求發(fā)布到服務器端。目前,消費者方面的工作已經完成。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號