spring cloud contract 使用
生產(chǎn)端
http spring cloud contract 使用 product
[https://docs.spring.io/spring-cloud-contract]
生產(chǎn)端步驟
- pom輸入
To start working with Spring Cloud Contract, you can add the Spring Cloud Contract Verifier dependency and plugin to your build file, as the following example shows:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency>
以下清單顯示了如何添加插件,該插件應(yīng)放在文件的buildplugins部分中:```xml
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<!--用于構(gòu)建過程中插件自動生成測試用例的基類,BaseCase使用http基類-->
<baseClassForTests> com.xzg.test.scc.BaseCase</baseClassForTests>
</configuration>
</plugin>
- 對于HTTPstubs,契約定義了應(yīng)針對給定請求返回的響應(yīng)類型(考慮到HTTP方法底桂,URL腥光,標頭巴帮,狀態(tài)碼等)落包。以下示例顯示了Groovy和YAML中的HTTPstubs協(xié)定:
契約默認存放在test下resource的contracts目錄下
request:
method: PUT
url: /fraudcheck
body:
"client.id": 1234567890
loanAmount: 99999
headers:
Content-Type: application/json
matchers:
body:
- path: $.['client.id']
type: by_regex
value: "[0-9]{10}"
response:
status: 200
body:
fraudCheckStatus: "FRAUD"
"rejection.reason": "Amount too high"
headers:
Content-Type: application/json;charset=UTF-8
- 執(zhí)行命令將生成測試stubs測試類,用于測試肺缕,請求是否正確
mvn clean install
可以看到日志:
....
[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
同時可以在target的generated-test-source目錄下生成測試文件
@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");
}
- 完成后消費端既可直接使用
使用kafka消息中間件的scc
我們應(yīng)考慮三種主要情況:
方案1:沒有輸入消息會生成輸出消息。輸出消息由應(yīng)用程序內(nèi)部的組件(例如,調(diào)度程序)觸發(fā)同木。
方案2:輸入消息觸發(fā)輸出消息浮梢。
方案3:輸入消息已被使用,并且沒有輸出消息彤路。
- 注意spring cloud 以及maven plug版本問題
https://github.com/spring-cloud/spring-cloud-contract/issues/1664
測試使用方案2秕硝,
- 修改pom支持kafka
<dependencies>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--。洲尊。远豺。-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<!--用于構(gòu)建過程中插件自動生成測試用例的基類,BaseCase使用http基類-->
<baseClassForTests> com.xzg.test.scc.BaseCase</baseClassForTests>
<!--用于構(gòu)建過程中插件自動生成測試用例的基類坞嘀,下面使用test mesage下的契約的基類躯护,用于kafka-->
<baseClassMappings>
<baseClassMapping>
<contractPackageRegex>.*message.*</contractPackageRegex>
<baseClassFQN>com.xzg.test.scc.BaseKafkaCase</baseClassFQN>
</baseClassMapping>
</baseClassMappings>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<!--用于指定自動生成測試類的目錄-->
<execution>
<id>add-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-test-sources/contracts/</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 編寫契約
# Human readable description
description: Some description
# Label by means of which the output message can be triggered
label: some_label
# input is a message
input:
messageFrom: kafka_topic
# has the following body
messageBody:
bookName: 'foo'
# and the following headers
messageHeaders:
sample: 'header'
# output message of the contract
outputMessage:
# destination to which the output message will be sent
sentTo: kafka_topic
# the body of the output message
body:
bookName: foo
# the headers of the output message
headers:
BOOK-NAME: foo
- 測試生成測試
mvn clean install -DTest
- 查看編譯后自動生成測試類
target/generated-test-source/contracts/
package com.xzg.test.scc;
import com.xzg.test.scc.BaseKafkaCase;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import org.junit.Test;
import org.junit.Rule;
import javax.inject.Inject;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging;
import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat;
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*;
import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;
import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers;
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes;
@SuppressWarnings("rawtypes")
public class MessageTest extends BaseKafkaCase {
@Inject ContractVerifierMessaging contractVerifierMessaging;
@Inject ContractVerifierObjectMapper contractVerifierObjectMapper;
@Test
public void validate_inputmessage() throws Exception {
// given:
ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
"{\"bookName\":\"foo\"}"
, headers()
.header("sample", "header")
);
// when:
contractVerifierMessaging.send(inputMessage, "kafka_topic");
// then:
ContractVerifierMessage response = contractVerifierMessaging.receive("kafka_topic");
assertThat(response).isNotNull();
// and:
assertThat(response.getHeader("BOOK-NAME")).isNotNull();
assertThat(response.getHeader("BOOK-NAME").toString()).isEqualTo("foo");
// and:
DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()));
assertThatJson(parsedJson).field("['bookName']").isEqualTo("foo");
}
@Test
public void validate_trigger() throws Exception {
// when:
trigger();
// then:
ContractVerifierMessage response = contractVerifierMessaging.receive("kafka_topic");
assertThat(response).isNotNull();
// and:
assertThat(response.getHeader("BOOK-NAME")).isNotNull();
assertThat(response.getHeader("BOOK-NAME").toString()).isEqualTo("foo");
assertThat(response.getHeader("contentType")).isNotNull();
assertThat(response.getHeader("contentType").toString()).isEqualTo("application/json");
// and:
DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()));
assertThatJson(parsedJson).field("['bookName']").isEqualTo("foo");
}
}
注意:編譯會自動將生成stub.jar上傳到本地maven倉庫。消費者端使用也是通過拉去本地測試丽涩。如果想要推送到遠程倉庫棺滞,需要單獨修改Spring Cloud Contract Stub Runner properties。另一種方式也可以使用git推送内狸,本地拉去編譯
[示例源碼地址](xiongzhenggang/spring-cloud-contract-example (github.com)
)