分类
商品
商品
店铺
资讯
分类
商品
商品
店铺
资讯

用Spring Boot的消费者驱动合同

摘要:在本文中,我们将探讨消费者驱动开发的细节。#问题主要问题是基于API接口上的消费者和生产者之间的冲突,当开发任何api时,你应该考虑的是你的用户的舒适度。假如你所做的更改打破了用户端的体验,那完全是一个笑话,本文探讨了消费者和生产者服务之间这种协议挑战。#处理之道消费者驱动合同(CDC)是确保生产者

在本文中,我们将探讨消费者驱动开发的细节。

#问题

主要问题是基于API接口上的消费者和生产者之间的冲突,当开发任何api时,你应该考虑的是你的用户的舒适度。假如你所做的更改打破了用户端的体验,那完全是一个笑话,本文探讨了消费者和生产者服务之间这种协议挑战。

#处理之道

消费者驱动合同(CDC)是确保生产者和消费者之间、分布式系统或者微服务中基于HTTP或者基于消息或者基于事件的软件之间的执行正确的协议合约或者合同。

Spring Cloud Contract是基于JVM的语言的CDC开发的实现,它也支持非基于jvm的语言,它将TDD提升到软件(api)设计和架构的水平,我称之为CDC - > Client Driven Development,由于是用户端(消费者)驱动生产者API的变化。

#为什么?

有关上面提到的少量问题和处理方案,你可能想为什么我们需要这种方法?消费者和生产者之间的握手在微服务架构设计存在少量挑战,由于,生产者所做的改变很难在消费者方面进行测试。见下面这个微服务图片:

当试图测试与许多其余服务进行通信的应使用程序时,我们可以在没有消费者驱动合同的情况下做以下事情:

1. 部署所有微服务并执行端到端测试。

2. 在测试中模拟Mock其余服务。

两种方法都有其优点和缺点。

部署所有微服务;

优点 - >模拟生产,测试实际服务,更可靠

缺点 - >长期运行,难以调试,许多成本(部署许多应使用程序,许多资源,如数据库,缓存等),存在非常晚的反馈

模拟Mock其余服务;

优点 - >非常快速的反馈,无需设置基础设备

缺点 - >不可靠,你可以对K8s的prod测试和失败检查

为处理这些问题,创立了Spring Cloud Contract。

我在开发应使用程序的新功能时遵循这些步骤;

1. 准备合同。

2. 从准备好的合同中生成测试。

3. 采使用TDD和红绿色风格编码。

4. 功能完成后,你可以创立存根(合约)jar。

5. 消费者可以用这个存根罐来集成api。

好吧,让我们按这个步骤编码;

首先,我们需要用Groovy DSL建立合同,如下所示;

importorg.springframework.cloud.contract.spec.Contract

Contract.make {

description"should retrieve account"

request {

method GET()

headers {

accept(applicationJson())

}

url ('/api/v1/accounts'){

queryParameters {

parameter(

"accountId",1L)

}

}

}

response {

status OK()

headers {

contentType(applicationJson())

}

body(file(

"retrieveAccountResponse.json"))

}

}

这是一个在生产者端检索帐户的合同定义,我们为检索帐户制作了这个样本合同。请求'api/v1/accounts'端点是用HTTP get方法和查询参数'accountId。

响应中指定Http标头为json,最后我们期望响应状态应该是正常的(200)并且响应头contentType应该是json并且响应体应该等于json响应文件。响应内容如下;

{

"name": "Name",

"surname": "Surname",

"gender": "Gender",

"gsmNumber": "GsmNumber",

"identifier": "Identifier",

"createdDate":1514851199,

"updatedDate":1514851199

}

在生成测试类之前,我们应该配置合同插件;

org.springframework.cloud

spring-cloud-starter-contract-verifier

test

org.springframework.boot

spring-boot-maven-plugin

org.springframework.cloud

spring-cloud-contract-maven-plugin

true


com.caysever.producer.ProducerBaseContractTest

EXPLICIT

生产者方面的pom.xml

你可以用TDD样式从合同和编码中生成测试类,这可以通过generateTests maven目标来做到这一点 - > mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:2.0.1.RELEASE:generateTests

生成的测试置于target/generated-test-sources下,生成测试如下代码:

publicclassContractVerifierTestextendsProducerBaseContractTest {

@Test

publicvoidvalidate_retrieveAccountContract() throws Exception {

//given:

RequestSpecification request =given()

.header(

"Accept", "application/json");

//when:

Response response =given().spec(request)

.queryParam(

"accountId","1")

.get(

"/api/v1/accounts");

//then:

assertThat(response.statusCode()).isEqualTo(200);

assertThat(response.header(

"Content-Type")).matches("application/json.*");

//and:

DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());

assertThatJson(parsedJson).field(

"['surname']").isEqualTo("Surname");

assertThatJson(parsedJson).field(

"['updatedDate']").isEqualTo(1514851199);

assertThatJson(parsedJson).field(

"['gender']").isEqualTo("Gender");

assertThatJson(parsedJson).field(

"['name']").isEqualTo("Name");

assertThatJson(parsedJson).field(

"['createdDate']").isEqualTo(1514851199);

assertThatJson(parsedJson).field(

"['identifier']").isEqualTo("Identifier");

assertThatJson(parsedJson).field(

"['gsmNumber']").isEqualTo("GsmNumber");

}

你现在可以将其作为正常的junit测试运行,测试通过后,可以与你的用户和消费者分享你的合同。

注意:

当修改端点(如重命名url或者增加/删除参数)时,应修改合同,假如你不修改,则构建无法通过。

Spring cloud contract插件为你生成存根stub的jar包,可以将其部署到artifactory或者本地参考local repo,Spring云契约支持不同的存根模式,例如classpath或者本地m2 repo或者远程artifactory(神器?),我们这里将用本地m2模式。

让我们看看如何消费存根stub:

@ExtendWith(SpringExtension.class)

@AutoConfigureWebTestClient

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

@AutoConfigureStubRunner(ids ="com.caysever:producer:+:8090", stubsMode = StubRunnerProperties.StubsMode.LOCAL)

classProducerVerifierTest {

@Autowired

privateWebTestClient webTestClient;

@Test

voidshould_retrieveAccountById() {

//given

? ? ? ? Long accountId = 1L;


//when

? ? ? ? Account account = webTestClient.get()

? ? ? ? ? ? ? ? .uri(

"http://localhost:8090/api/v1/accounts?accountId={accountId}", accountId)

? ? ? ? ? ? ? ? .accept(MediaType.APPLICATION_JSON)

? ? ? ? ? ? ? ? .exchange()

? ? ? ? ? ? ? ? .expectStatus().isOk()

? ? ? ? ? ? ? ? .expectBody(Account.class)

? ? ? ? ? ? ? ? .returnResult()

? ? ? ? ? ? ? ? .getResponseBody();


//then

? ? ? ? assertThat(account).isNotNull();

? ? ? ? assertThat(account.getName()).isEqualTo(

"Name");

? ? ? ? assertThat(account.getSurname()).isEqualTo(

"Surname");

? ? ? ? assertThat(account.getGender()).isEqualTo(

"Gender");

? ? ? ? assertThat(account.getGsmNumber()).isEqualTo(

"GsmNumber");

? ? ? ? assertThat(account.getIdentifier()).isEqualTo(

"Identifier");

? ? ? ? assertThat(account.getCreatedDate()).isEqualTo(1514851199);

? ? ? ? assertThat(account.getUpdatedDate()).isEqualTo(1514851199);

? ? }

}

用@AutoConfigureStubRunner注释Spring设置wiremock服务器,真正的生产者api应该在8090端口,我们创立REST http请求并断言响应数据。假如任何步骤发生失败,则测试交付的CI / CD管道都不会通过,即便在你的本地环境而不是CI服务器上

Java高架构师、分布式架构、高可扩展、高性能、高并发、性能优化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战学习架构师视频免费获取

进阶高级架构群;855355016

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】极客时间-数据分析实战45讲【完结】(2021-09-02 16:26)
【系统环境|windows】字节跳动前台面试题解析:盛最多水的容器(2021-03-20 21:27)
【系统环境|windows】DevOps敏捷60问,肯定有你想理解的问题(2021-03-20 21:27)
【系统环境|windows】字节跳动最爱考的前台面试题:JavaScript 基础(2021-03-20 21:27)
【系统环境|windows】JavaScript 的 switch 条件语句(2021-03-20 21:27)
【系统环境|windows】解决 XML 数据应用实践(2021-03-20 21:26)
【系统环境|windows】20个编写现代CSS代码的建议(2021-03-20 21:26)
【系统环境|windows】《vue 3.0探险记》- 运行报错:Error:To install them, you can run: npm install --save core-js/modules/es.arra...(2021-03-20 21:24)
【系统环境|windows】浅谈前台可视化编辑器的实现(2021-03-20 21:24)
【系统环境|windows】产品经理入门迁移学习指南(2021-03-20 21:23)
手机二维码手机访问领取大礼包
返回顶部