關鍵詞:
- Spring Cloud Contract:一個CDC Testing框架,類似的還有Pact
- CDC:
Consumer Driven ContractTesting - Provider:
服務提供方 - Consumer:
服務調(diào)用方
什么是契約測試
微服務系統(tǒng)由大量的微服務節(jié)點組成,對其中一個服務節(jié)點做測試,需要部署依賴的服務節(jié)點,實際應用中會有以下的問題:
- 依賴服務沒有開發(fā)完成,無法部署,導致無法測試。
- 依賴服務不穩(wěn)定(測試環(huán)境問題、部署異常、數(shù)據(jù)問題等等),導致測試不通過。
- 依賴的服務發(fā)生變化沒有知會到調(diào)用服務的一方,導致測試不通過。
在這次測試中,我們定義調(diào)用服務或者說消費服務的一方為Consumer,而依賴的服務提供方為Provider
針對以上問題,CDC主要定義了以下特性:
- Consumer根據(jù)自己的對Provider的期望編寫Contract
- Provider根據(jù)Contract實現(xiàn)接口并進行測試(CDC框架可以根據(jù)Contract自動生成測試代碼用于驗證Provider提供的服務是否和Contract一致)
- Provider根據(jù)Contract生成Stubs實現(xiàn)對Provider進行Mock。
Sping Cloud Contract代碼實例
一、通過契約驗證Provider的服務和Contract是否一致
Provider引入依賴
引入依賴到/src/test目錄所在模塊的pom.xml中
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<version>2.2.4.RELEASE</version>
<scope>test</scope>
</dependency>
實際如下圖

引入plugin到/src/test目錄所在模塊的pom.xml中
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>2.2.4.RELEASE</version>
<extensions>true</extensions>
<configuration>
<baseClassForTests>com.alibaba.cxdc.qxc.sweetnurse.BaseMock</baseClassForTests>
</configuration>
</plugin>
如下圖:

Provider端編寫契約
契約可以使用groovy(推薦)或者YAML編寫,我的契約文件存放路徑為src/test/resources/contracts

契約對應的provider接口為:

Provider端根據(jù)Contract自動生成Test Class
執(zhí)行命令:mvn clean install


生成的stubs.jar會自動安裝到本地Maven倉庫(
.m2/repository):
執(zhí)行生成的Test驗證Provider提供的服務和Contract定義是否一致
執(zhí)行命令:mvn clean install或者mvn test時,會根據(jù)契約驗證provider提供的服務是否和契約描述的一致:
1.契約描述返回值為xxx,實際接口返回為ceshi,所以test執(zhí)行不通過:

2.修改契約文件如下:

3.驗證通過:

后續(xù)如果Provider接口發(fā)生了變化,測試會驗證不通過。
二、Consumer基于stubs進行mock測試
安裝stubs.jar到本地Maven倉庫
Provider的目錄下執(zhí)行命令mvn clean install會自動安裝stub包到本地Maven倉庫

本文中stubs.jar的Maven坐標如下:
- groupId:
com.alibaba.cxdc.qxc - artifactId:
sweetnurse-start - version:
1.0.0 - classfier:
stubs
Consumer端引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
編寫Consumer的測試類
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.LOCAL,
ids = "com.alibaba.cxdc.qxc:sweetnurse-start:1.0.0:stubs:10001")
public class StubTest {
private String url = "http://localhost:10001";
@Test
public void testMethod() throws Exception {
RestTemplate restTemplate = new RestTemplate();
JSONObject param = new JSONObject();
param.put("contract", "ceshi");
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<JSONObject> entity = new HttpEntity<>(param,requestHeaders);
ResponseEntity<String> result = restTemplate.postForEntity(url + "/rest/workshift/sayHello", entity,
String.class);
System.out.println(result.getStatusCode());
}
}
實際代碼如圖:

執(zhí)行結(jié)果如圖:

AutoConfigureStubRunner注解及內(nèi)部屬性的含義:
1.@AutoConfigureStubRunner:根據(jù)ids屬性獲取stubs.jar并啟動web服務器供測試mock調(diào)用
2.ids的含義
ids = "com.alibaba.cxdc.qxc:sweetnurse-start:1.0.0:stubs:10001
ids = "groupId:artifactId:version:classfier:port"
其中version如果用+表示取最新版本
3.stubsMode的含義:
StubRunnerProperties.StubsMode.LOCAL:從本地的maven倉庫獲取stubs.jar
StubRunnerProperties.StubsMode.REMOTE:從遠程maven倉庫獲取stubs.jar
StubRunnerProperties.StubsMode.CLASSPATH:默認值、從本地java classpath獲取stubs.jar
參考文檔:
Spring Cloud Contract Referenct
Pact
What's Next?
1.Pact框架和Spring Cloud Contract區(qū)別,針對不同語言的適用性是否更好。
2.怎么在現(xiàn)有自動化測試平臺中實現(xiàn)或者集成契約測試能力。