Spring Cloud Contract簡介
1.簡介
簡而言之, Spring Cloud Contract是一個項目,可以幫助我們編寫“消費者驅動的合同”(CDC) 。
這樣可以確保在分佈式系統中, Producer
與Consumer
之間的合同既基於HTTP交互又基於消息交互。
在這篇快速的文章中,我們將探索通過HTTP交互為Spring Cloud Contract編寫生產方和消費者方測試用例。
2.生產者–服務器端
我們將以EvenOddController
的形式編寫一個生產方CDC –它只是告訴number
參數是偶數還是奇數:
@RestController
public class EvenOddController {
@GetMapping("/validate/prime-number")
public String isNumberPrime(@RequestParam("number") Integer number) {
return Integer.parseInt(number) % 2 == 0 ? "Even" : "Odd";
}
}
2.1。 Maven依賴
對於我們的生產者端,我們需要spring-cloud-starter-contract-verifier
依賴項:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<version>2.1.1.RELEASE</version>
<scope>test</scope>
</dependency>
而且,我們需要使用基本測試類的名稱來配置spring-cloud-contract-maven-plugin
,我們將在下一部分中對其進行描述:
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<extensions>true</extensions>
<configuration>
<baseClassForTests>
com.baeldung.spring.cloud.springcloudcontractproducer.BaseTestClass
</baseClassForTests>
</configuration>
</plugin>
2.2。生產者端設置
我們需要在測試包中添加一個基類來加載我們的Spring上下文:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@DirtiesContext
@AutoConfigureMessageVerifier
public class BaseTestClass {
@Autowired
private EvenOddController evenOddController;
@Before
public void setup() {
StandaloneMockMvcBuilder standaloneMockMvcBuilder
= MockMvcBuilders.standaloneSetup(evenOddController);
RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
}
}
在/src/test/resources/contracts/
包中,我們將在文件shouldReturnEvenWhenRequestParamIsEven.groovy
添加測試存根,例如該存根:
import org.springframework.cloud.contract.spec.Contract
Contract.make {
description "should return even when number input is even"
request{
method GET()
url("/validate/prime-number") {
queryParameters {
parameter("number", "2")
}
}
}
response {
body("Even")
status 200
}
}
當我們運行構建時,**插件會自動生成一個名為ContractVerifierTest
的測試類,該類擴展了BaseTestClass
**並將其放在/target/generated-test-sources/contracts/
。
測試方法的名稱是從前綴“ validate_”
派生而來的,該前綴與我們的Groovy測試存根的名稱連接在一起。對於上述Groovy文件,生成的方法名稱將為“validate_shouldReturnEvenWhenRequestParamIsEven”
。
讓我們看一下這個自動生成的測試類:
public class ContractVerifierTest extends BaseTestClass {
@Test
public void validate_shouldReturnEvenWhenRequestParamIsEven() throws Exception {
// given:
MockMvcRequestSpecification request = given();
// when:
ResponseOptions response = given().spec(request)
.queryParam("number","2")
.get("/validate/prime-number");
// then:
assertThat(response.statusCode()).isEqualTo(200);
// and:
String responseBody = response.getBody().asString();
assertThat(responseBody).isEqualTo("Even");
}
該構建還將在我們的本地Maven存儲庫中添加存根jar,以便我們的使用者可以使用它。
存根將出現在stubs/mapping/
下的輸出文件夾中。
3.消費者–客戶端
CDC的消費者方將使用生產者方通過HTTP交互生成的存根來維護合同,因此,生產者方的任何更改都將破壞合同。
我們將添加BasicMathController,
它將發出HTTP請求以從生成的存根中獲取響應:
@RestController
public class BasicMathController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/calculate")
public String checkOddAndEven(@RequestParam("number") Integer number) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/json");
ResponseEntity<String> responseEntity = restTemplate.exchange(
"http://localhost:8090/validate/prime-number?number=" + number,
HttpMethod.GET,
new HttpEntity<>(httpHeaders),
String.class);
return responseEntity.getBody();
}
}
3.1。 Maven的依賴
對於我們的消費者,我們需要添加spring-cloud-contract-wiremock
和spring-cloud-contract-stub-runner
依賴項:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-wiremock</artifactId>
<version>2.1.1.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-stub-runner</artifactId>
<version>2.1.1.RELEASE</version>
<scope>test</scope>
</dependency>
3.2。消費者方設置
現在是時候配置我們的存根運行程序,它將通知我們的使用者我們本地Maven存儲庫中的可用存根:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
@AutoConfigureStubRunner(
stubsMode = StubRunnerProperties.StubsMode.LOCAL,
ids = "com.baeldung.spring.cloud:spring-cloud-contract-producer:+:stubs:8090")
public class BasicMathControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void given_WhenPassEvenNumberInQueryParam_ThenReturnEven()
throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/calculate?number=2")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string("Even"));
}
}
請注意, @AutoConfigureStubRunner
批註的ids
屬性指定:
-
com.baeldung.spring.cloud
—我們工件的groupId
-
spring-cloud-contract-producer
—生產者存根罐的artifactId
-
8090
—生成的存根將在其上運行的端口
4.當合同失敗時
如果我們在生產方進行任何直接影響合同的更改而不更新消費者方,則可能導致合同失敗。
例如,假設我們要在生產者端將EvenOddController
請求URI /validate/change/prime-number
為/validate/change/prime-number
。
如果我們無法將此更改通知消費者,則消費者仍將其請求發送到/validate/prime-number
URI,並且消費者方測試用例將拋出org.springframework.web.client.HttpClientErrorException: 404 Not Found
。
5.總結
我們已經看到了Spring Cloud Contract如何能夠幫助我們維護服務使用者和生產者之間的合同,以便我們可以推出新代碼而不必擔心違反合同。
而且,與往常一樣,可以在GitHub上找到本教程的完整實現。