W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
作為貸款發(fā)行服務(wù)的開發(fā)人員(欺詐檢測(cè)服務(wù)器的使用者),您可以執(zhí)行以下步驟:
通過(guò)為您的功能編寫測(cè)試來(lái)開始進(jìn)行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"); }
假設(shè)您已經(jīng)編寫了新功能的測(cè)試。如果收到大量貸款申請(qǐng),則系統(tǒng)應(yīng)拒絕該貸款申請(qǐng)并提供一些說(shuō)明。
編寫缺少的實(shí)現(xiàn)。
在某個(gè)時(shí)間點(diǎn),您需要向欺詐檢測(cè)服務(wù)發(fā)送請(qǐng)求。假設(shè)您需要發(fā)送包含客戶ID和客戶希望借入的金額的請(qǐng)求。您想通過(guò)PUT
方法將其發(fā)送到/fraudcheck
網(wǎng)址。
ResponseEntity<FraudServiceResponse> response = restTemplate.exchange( "http://localhost:" + port + "/fraudcheck", HttpMethod.PUT, new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class);
為簡(jiǎn)單起見,欺詐檢測(cè)服務(wù)的端口設(shè)置為8080
,應(yīng)用程序在8090
上運(yùn)行。
如果此時(shí)開始測(cè)試,則會(huì)中斷測(cè)試,因?yàn)楫?dāng)前沒有服務(wù)在端口8080
上運(yùn)行。
在本地克隆欺詐檢測(cè)服務(wù)存儲(chǔ)庫(kù)。
您可以從服務(wù)器端合同開始。為此,您必須首先克隆它。
$ git clone https://your-git-server.com/server-side.git local-http-server-repo
在欺詐檢測(cè)服務(wù)的倉(cāng)庫(kù)中本地定義合同。
作為消費(fèi)者,您需要定義要實(shí)現(xiàn)的目標(biāo)。您需要制定自己的期望。為此,請(qǐng)編寫以下合同:
將合同放在
src/test/resources/contracts/fraud
文件夾下。fraud
文件夾很重要,因?yàn)樯a(chǎn)者的測(cè)試基類名稱引用了該文件夾。
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合同很簡(jiǎn)單。但是,當(dāng)您查看使用靜態(tài)類型的Groovy DSL編寫的合同時(shí)-您可能會(huì)懷疑value(client(…?), server(…?))
部分是什么。通過(guò)使用此表示法,Spring Cloud Contract使您可以定義JSON塊,URL等動(dòng)態(tài)的部分。如果是標(biāo)識(shí)符或時(shí)間戳,則無(wú)需對(duì)值進(jìn)行硬編碼。您要允許一些不同的值范圍。要啟用值范圍,可以為使用者方設(shè)置與這些值匹配的正則表達(dá)式。您可以通過(guò)地圖符號(hào)或帶插值的字符串來(lái)提供主體。有關(guān)更多信息,請(qǐng)參見Contract DSL部分。我們強(qiáng)烈建議您使用地圖符號(hào)!
您必須了解地圖符號(hào)才能設(shè)置合同。請(qǐng)閱讀有關(guān)JSON的 Groovy文檔。
前面顯示的合同是雙方之間的協(xié)議,其中:
如果HTTP請(qǐng)求與所有
/fraudcheck
端點(diǎn)上的PUT
方法,client.id
且與正則表達(dá)式[0-9]{10}
和loanAmount
等于99999
匹配的JSON正文,application/vnd.fraud.v1+json
的Content-Type
標(biāo)頭,然后將HTTP響應(yīng)發(fā)送給使用者
200
,fraudCheckStatus
字段包含值FRAUD
,而rejectionReason
字段包含值Amount too high
,Content-Type
標(biāo)頭,其值為application/vnd.fraud.v1+json
。一旦準(zhǔn)備好在集成測(cè)試中實(shí)際檢查API,就需要在本地安裝存根。
添加Spring Cloud Contract驗(yàn)證程序插件。
我們可以添加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>
接下來(lái),添加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>
自從添加了插件以來(lái),您將獲得Spring Cloud Contract Verifier
功能,這些功能來(lái)自提供的合同:
您不想生成測(cè)試,因?yàn)樽鳛橄M(fèi)者,您只想玩存根。您需要跳過(guò)測(cè)試的生成和執(zhí)行。執(zhí)行時(shí):
$ cd local-http-server-repo
$ ./mvnw clean install -DskipTests
在日志中,您會(huì)看到以下內(nèi)容:
[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
它確認(rèn)http-server
的存根已安裝在本地存儲(chǔ)庫(kù)中。
運(yùn)行集成測(cè)試。
為了從自動(dòng)存根下載的Spring Cloud Contract Stub Runner功能中受益,您必須在用戶端項(xiàng)目(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>
將依賴項(xiàng)添加到Spring Cloud Contract Stub Runner
:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-stub-runner</artifactId> <scope>test</scope> </dependency>
用@AutoConfigureStubRunner
注釋測(cè)試類。在注釋中,為Stub Runner提供group-id
和artifact-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)在,當(dāng)您運(yùn)行測(cè)試時(shí),您將看到類似以下的內(nèi)容:
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找到了您的存根,并為您的應(yīng)用啟動(dòng)了服務(wù)器,其組ID為com.example
,工件ID為??http-server
,存根的版本為0.0.1-SNAPSHOT
,且分類器為stubs
端口8080
。
提出拉取請(qǐng)求。
到目前為止,您所做的是一個(gè)迭代過(guò)程。您可以試用合同,將其安裝在本地,然后在用戶端工作,直到合同按您的意愿運(yùn)行。
對(duì)結(jié)果滿意并通過(guò)測(cè)試后,將拉取請(qǐng)求發(fā)布到服務(wù)器端。目前,消費(fèi)者方面的工作已經(jīng)完成。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: