spring 消息传递机制_Spring再次涵盖了您:继续进行消费者驱动的消息传递合同测试...
spring 消息传递机制
在上一篇文章中,我们已经开始讨论基于消息的通信中的消费者驱动的合同测试 。 在今天的帖子中,我们将在测试工具箱中包含另一个工具,但是在此之前,让我对显微镜下的系统进行快速回顾。 它有两项服务, 订单服务和货运服务 。 订单服务将消息/事件发布到消息队列,然后运货服务从那里使用它们。
通过寻找合适的测试支架,我们发现了Pact框架(准确地说是Pact JVM )。 该协议提供了编写消费者和生产者测试的简单明了的方法,没有为不进行消费者驱动的合同测试提供任何借口。 但是,该领域还有另一个参与者Spring Cloud Contract ,这就是我们今天要讨论的内容。
首先, Spring Cloud Contract适合基于最佳的基于JVM的项目,该项目建立在出色的Spring产品组合之上(尽管您也可以使其在多语言场景中工作)。 另外, Spring Cloud Contract采用的协作流程与Pact教给我们的协作流程略有不同,这不一定是一件坏事。 让我们直接说清楚。
由于我们只研究消息传递,因此Spring Cloud Contract要求我们要做的第一件事就是定义消息传递协议规范,该规范是使用便捷的Groovy Contract DSL编写的。
package contracts org.springframework.cloud.contract.spec.Contract.make { name "OrderConfirmed Event" label 'order' input { 'createOrder()' triggeredBy( 'createOrder()' ) } outputMessage { sentTo 'orders' body([ orderId: $(anyUuid()), paymentId: $(anyUuid()), amount: $(anyDouble()), street: $(anyNonBlankString()), city: $(anyNonBlankString()), state: $(regex( '[AZ]{2}' )), zip: $(regex( '[0-9]{5}' )), country: $(anyOf( 'USA' , 'Mexico' )) ]) headers { header( 'Content-Type' , 'application/json' ) } } }
它类似于我们已经熟悉的许多Pact规范(如果您不是Groovy的忠实拥护者 ,则不需要真正学习它即可使用Spring Cloud Contract )。 这里有趣的部分是triggeredBy和sentTo块:基本上,这些轮廓是如何被生成的消息(或触发),并且其中它应该分别着陆(通道或队列名称)。 在这种情况下, createOrder()只是方法名称,我们必须为其提供实现。
package com.example.order; import java.math.BigDecimal; import java.util.UUID; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier; import org.springframework.integration.support.MessageBuilder; import org.springframework.messaging.MessageChannel; import org.springframework.test.context.junit4.SpringRunner; import com.example.order.event.OrderConfirmed; @RunWith (SpringRunner. class ) @SpringBootTest @AutoConfigureMessageVerifier public class OrderBase { @Autowired private MessageChannel orders; public void createOrder() { final OrderConfirmed order = new OrderConfirmed(); order.setOrderId(UUID.randomUUID()); order.setPaymentId(UUID.randomUUID()); order.setAmount( new BigDecimal( "102.32" )); order.setStreet( "1203 Westmisnter Blvrd" ); order.setCity( "Westminster" ); order.setCountry( "USA" ); order.setState( "MI" ); order.setZip( "92239" ); orders.send( MessageBuilder .withPayload(order) .setHeader( "Content-Type" , "application/json" ) .build()); } }
不过,这里只剩下一个小细节:这些合同是由提供者(或更确切地说,生产者)而不是消费者来管理的。 不仅如此,生产者有责任为消费者发布所有存根,以便他们能够针对其编写测试。 当然,与Pact所采用的路径不同,但是从好的方面来说,针对生产者的测试套件是由Apache Maven / Gradle插件100%生成的。
< plugin > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-contract-maven-plugin</ artifactId > < version >2.1.4.RELEASE</ version > < extensions >true</ extensions > < configuration > < packageWithBaseClasses >com.example.order</ packageWithBaseClasses > </ configuration > </ plugin >
您可能已经注意到,该插件将假定基本测试类(必须提供createOrder()方法实现的那些类)位于com.example.order包中,即我们放置OrderBase类的确切位置。 要完成设置,我们需要向pom.xml文件中添加一些依赖项。
< dependencyManagement > < dependencies > < dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-dependencies</ artifactId > < version >Greenwich.SR4</ version > < type >pom</ type > < scope >import</ scope > </ dependency > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-dependencies</ artifactId > < version >2.1.10.RELEASE</ version > < type >pom</ type > < scope >import</ scope > </ dependency > </ dependencies > </ dependencyManagement > < dependencies > < dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-starter-contract-verifier</ artifactId > < scope >test</ scope > </ dependency > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-test</ artifactId > < scope >test</ scope > </ dependency > </ dependencies >
而且我们已经完成了生产者方面的工作! 如果我们现在运行mvn clean install ,将发生两件事。 首先,您会注意到已经运行并通过了一些测试,尽管我们没有编写任何测试,但这些测试都是以我们的名义生成的。
------------------------------------------------------- TESTS ------------------------------------------------------- Running com.example.order.OrderTest .... Results : Tests run: 1 , Failures: 0 , Errors: 0 , Skipped: 0
其次,也将生成(发布)针对消费者的存根(在这种情况下,将其捆绑到order-service-messaging-contract-tests-0.0.1-SNAPSHOT-stubs.jar中 )。
... [INFO] [INFO] --- spring-cloud-contract-maven-plugin: 2.1 . 4 .RELEASE:generateStubs ( default -generateStubs) @ order-service-messaging-contract-tests --- .RELEASE:generateStubs ( [INFO] Files matching this pattern will be excluded from stubs generation [] [INFO] Files matching pattern will be excluded from stubs generation [] [INFO] Building jar: order-service-messaging-contract-tests- 0.0 . 1 -SNAPSHOT-stubs.jar [INFO] ....
太好了,因此我们已经发布了消息传递合同规范和存根,现在就在消费者的领域,即Shipment Service 。 消费者最棘手的部分可能是配置所选的消息传递集成库。 在我们的案例中,它将是Spring Cloud Stream,但是也可以使用其他集成 。
理解Spring Cloud Contract在消费者方面如何工作的最快方法是从头开始,并首先查看完整的示例测试套件。
@RunWith (SpringRunner. class ) @SpringBootTest @AutoConfigureMessageVerifier @AutoConfigureStubRunner ( ids = "com.example:order-service-messaging-contract-tests:+:stubs" , stubsMode = StubRunnerProperties.StubsMode.LOCAL ) public class OrderMessagingContractTest { @Autowired private MessageVerifier<Message<?>> verifier; @Autowired private StubFinder stubFinder; @Test public void testOrderConfirmed() throws Exception { stubFinder.trigger( "order" ); final Message<?> message = verifier.receive( "orders" ); assertThat(message, notNullValue()); assertThat(message.getPayload(), isJson( allOf(List.of( withJsonPath( "$.orderId" ), withJsonPath( "$.paymentId" ), withJsonPath( "$.amount" ), withJsonPath( "$.street" ), withJsonPath( "$.city" ), withJsonPath( "$.state" ), withJsonPath( "$.zip" ), withJsonPath( "$.country" ) )))); } }
在最上方, @AutoConfigureStubRunner引用生产者发布的存根,有效地来自order-service-messaging-contract-tests-0.0.1-SNAPSHOT-stubs.jar存档中的存根 。 StubFinder通过调用stubFinder.trigger(“ order”)帮助我们为测试用例选择正确的存根,并触发特定的消息传递合同验证流程。 “ order”值不是任意的,它应与分配给合同规范的标签匹配,在我们的示例中,我们将其定义为:
package contracts org.springframework.cloud.contract.spec.Contract.make { ... label 'order' ... }
这样,测试应该看起来简单而直接:触发流程,验证消息是否已放入消息传递通道并满足消费者的期望。 从配置的角度来看,我们只需要提供此消息传递通道即可运行测试。
@SpringBootConfiguration public class OrderMessagingConfiguration { @Bean PollableChannel orders() { return MessageChannels.queue().get(); } }
再说一次,bean的名称orders不是一个随机选择,它必须从合同规范中获取很多目的地:
package contracts org.springframework.cloud.contract.spec.Contract.make { ... outputMessage { sentTo 'orders' ... } ... }
最后但并非最不重要的一点,让我们枚举使用者方面所需的依赖关系(幸运的是,无需使用任何其他的Apache Maven或Gradle插件)。
< dependencyManagement > < dependencies > < dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-dependencies</ artifactId > < version >Greenwich.SR4</ version > < type >pom</ type > < scope >import</ scope > </ dependency > </ dependencies > </ dependencyManagement > < dependencies > < dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-starter-contract-verifier</ artifactId > < scope >test</ scope > </ dependency > < dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-starter-contract-stub-runner</ artifactId > < scope >test</ scope > </ dependency > < dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-stream</ artifactId > < version >2.2.1.RELEASE</ version > < type >test-jar</ type > < scope >test</ scope > < classifier >test-binder</ classifier > </ dependency > </ dependencies >
在这里快速说明。 最后一个依赖关系是一个很重要的难题,它带来了Spring Cloud Stream与Spring Cloud Contract的集成。 这样,消费者就全都准备好了。
------------------------------------------------------- TESTS ------------------------------------------------------- Running com.example.order.OrderMessagingContractTest ... Results : Tests run: 1 , Failures: 0 , Errors: 0 , Skipped: 0
为了结束循环,我们应该回顾消费者驱动的合同测试的核心承诺之一:允许生产者在不破坏消费者的情况下发展合同。 实际上,这意味着消费者可以将测试归还给生产者,尽管这样做的轻率性与Spring Cloud Contract无关 。 原因很简单:生产者是那些首先编写消息合同规范的人,并且期望从这些规范中生成的测试无法抵御任何重大更改。 尽管如此,对于生产者来说,了解消费者如何使用他们的消息还是有很多好处的,所以请给我一些想法。
满怀希望,这是一个有趣的话题。 Spring Cloud Contract带来了将消费者驱动的合约测试应用于消息传递的不同观点。 它是Pact JVM的一个有吸引力的替代方法,特别是如果您的应用程序和服务已经依赖Spring项目 。
与往常一样,完整的项目资源可在Github上找到 。
翻译自: https://www.javacodegeeks.com/2019/12/spring-covered-again-consumer-driven-contract-testing-messaging-continued.html
spring 消息传递机制
spring 消息传递机制_Spring再次涵盖了您:继续进行消费者驱动的消息传递合同测试...相关推荐
- Spring再次涵盖了您:继续进行消费者驱动的消息传递合同测试
在上一篇文章中,我们已经开始讨论基于消息的通信中的消费者驱动的合同测试 . 在今天的帖子中,我们将在测试工具箱中包含另一个工具,但是在此之前,让我对显微镜下的系统进行快速回顾. 它有两项服务, 订单服 ...
- 消费者驱动的契约测试_告诉我们您想要什么,我们将做到:消费者驱动的合同测试消息传递...
消费者驱动的契约测试 相当早以前,我们从REST(ful) Web API的角度讨论了消费者驱动的合同测试 ,尤其是将其投射到Java( JAX-RS 2.0规范)的角度. 可以公平地说,至少在公共A ...
- 告诉我们您想要什么,我们将做到:消费者驱动的合同测试消息传递
相当早以前,我们从REST(ful) Web API的角度讨论了消费者驱动的合同测试 ,尤其是将其投射到Java( JAX-RS 2.0规范)的角度. 可以公平地说,至少在公共API方面, REST仍 ...
- Golang和Erlang消息传递机制对比
上一篇文章介绍了 Go 和 Erlang 在调度器的实现,本文将简要介绍这两种并发语言的消息传递机制 简要对比 Erlang和Go虽然在实现及功能上差异较大,但是都支持高并发的轻量级用户任务(Erla ...
- retrofit2 spring接受参数_Spring面试中有可能遇到的问题
1. 细阐述Spring事务机制的实现原理? Spring的事务管理机制实现的原理,就是通过AOP,使用动态代理对所有需要事务管理的Bean进行加载,并根据配置在 拥抱自然,享受学习 invoke方法 ...
- android串口补位,Rust多线程中的消息传递机制
代码说话. use std::thread; use std::sync::mpsc; use std::time::Duration; fn main() { let (tx, rx) = mpsc ...
- Android Handler消息传递机制
Android中只允许UI线程(也就是主线程)修改Activity里的UI组件.实际开发中,新启动的线程需要周期性地改变界面组件的属性值就需要借助Handler的消息传递机制. Handler类 Ha ...
- Spring 事务机制详解
Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,仅供学习参考. Spring声明式事务让我们从复杂的事务处理中得到解脱.使得我们再也无 ...
- Spring事件机制详解
一.前言 说来惭愧,对应Spring事件机制之前只知道实现 ApplicationListener 接口,就可以基于Spring自带的事件做一些事情(如ContextRefreshedEvent),但 ...
最新文章
- zookeeper分布式锁代码实例
- django.core.exceptions.ImproperlyConfiguredmysqlclient 1.3.13 ornewer is required you have 0.9.2(亲测)
- QT--foreach的用法
- Office CVE-2017-11882复现
- LeetCode 面试题13. 机器人的运动范围
- Python钉钉报警及Zabbix集成钉钉报警
- warpaffine 旋转有一部分消失_如果月球消失了,会发生什么?我们的世界又将会变得怎么样?...
- 西门子uss通讯实例_西门子plc1200系列的功能特点有哪些?
- linux grub 删除文件,删除grub的方法(转)
- ORACLE自增字段创建方法
- buuct 假如给我三天光明 misc_【习作园地】假如给我三天光明读后感
- 决策树的简单实现与可视化
- 【TSP】基于matlab灰狼算法求解旅行商问题【含Matlab源码 1327期】
- 代码安全之代码混淆及加固(Android)
- 99%的人不知道!收藏这些自媒体实用网站,让你月薪提高5k
- 起风了数字简谱用计算机,起风了钢琴简谱-数字双手-买辣椒也用券
- 海洋cms播放器html,海洋cms升级新播放器后播放不了如何解决?
- 【入门PCB】立创eda的学习
- 小米3联通电信版解锁(2013062 2013063)刷机包可解账号锁
- python图片分析中央气象台降水量预报_获取中央气象台网的气象数据 全流程技术解析(python 爬虫)...
热门文章
- C - Insertion Sort Gym - 101955C
- P4158-[SCOI2009]粉刷匠【dp,背包】
- jzoj3783-[NOIP2014模拟8.19]签到题【结论题】
- ssl1213-多边形面积【差积,计算几何】
- USACO2.4のP1519-穿越栅栏(Overfencing)【bfs】
- 2021牛客暑期多校训练营4 E-Tree Xor(异或+思维+区间交 or Trie树)
- CVPR19 基于图卷积网络的多标签图像识别模型 论文笔记
- 2017西安交大ACM小学期数据结构 [线段树]
- 跟我学 Java 8 新特性之 Stream 流(二)关键知识点
- sleep( ) 和 wait( ) 的这 5 个区别,你知道几个