告诉我们您想要什么,我们将做到:消费者驱动的合同测试消息传递

相当早以前,我们从REST(ful) Web API的角度讨论了消费者驱动的合同测试 ,尤其是将其投射到Java( JAX-RS 2.0规范)的角度。 可以公平地说,至少在公共API方面, REST仍在Web API领域占据主导地位,然而,向微服务或/和基于服务的体系结构的转变正在Swift改变力量的一致性。 这种破坏性趋势之一是消息传递 。

现代的REST(ful) API主要通过HTTP 1.1协议实现,并受其请求/响应通信样式的限制。 这里提供了HTTP / 2的 帮助,但仍然不是每个用例都适合此通信模型。 通常,该工作可以异步执行,并且可以稍后将其完成的事实广播给感兴趣的各方。 这就是大多数事情在现实生活中的工作方式,使用消息传递是对此的完美答案。

消息传递空间确实挤满了惊人数量的消息代理和可用的无代理选项。 我们将不再谈论这个问题,而是专注于另一个棘手的主题:消息契约。 生产者发出消息或事件后,它将进入队列/主题/频道,准备被使用。 它在这里停留了一段时间。 显然,生产者知道它所发布的内容,但是消费者呢? 他们怎么知道会发生什么?

此刻,我们许多人会大喊:使用基于模式的序列化! 的确, Apache Avro , Apache Thrift , 协议缓冲区 , 消息包 …可以解决这个问题。 归根结底,此类消息和事件以及REST(ful) Web API(如果有)将成为提供程序合同的一部分,并且必须随着时间的推移进行通信和发展而不会破坏使用者。 但是……您会惊讶地发现,有多少组织在JSON中发现了他们的必杀技,并使用它来传递消息和事件, 从而向消费者扔出这样的垃圾 ,而没有任何模式! 在这篇文章中,我们将研究消费者驱动的合同测试技术如何在这种情况下为我们提供帮助。

让我们考虑一个简单的系统,它具有两项服务,即订单服务货运服务订单服务将消息/事件发布到消息队列,然后运货服务从那里使用它们。

由于Order Service是用Java实现的,因此事件只是POJO类,在使用众多库之一到达消息代理之前,序列化为JSON 。 OrderConfirmed是此类事件之一。

 public class OrderConfirmed { private UUID orderId; private UUID paymentId; private BigDecimal amount; private String street; private String city; private String state; private String zip; private String country;  } 

通常情况下, Shipment Service团队会提供示例JSON代码片段,或者指出一些文档或参考Java类,基本上就是这样。 在确定他们的解释正确无误且所需消息消息不会突然消失的同时,货运服务团队如何启动整合工作? 以消费者为导向的合同测试得以营救!

Shipment Service团队可以(并且应该)开始针对OrderConfirmed消息编写测试用例,并嵌入他们所拥有的知识,而我们的老朋友Pact框架(准确地说是Pact JVM )是实现这一目标的正确工具。 那么测试用例可能是什么样子?

 public class OrderConfirmedConsumerTest { private static final String PROVIDER_ID = "Order Service" ; private static final String CONSUMER_ID = "Shipment Service" ;     @Rule public MessagePactProviderRule provider = new MessagePactProviderRule( this ); private byte [] message; @Pact (provider = PROVIDER_ID, consumer = CONSUMER_ID) public MessagePact pact(MessagePactBuilder builder) { return builder .given( "default" ) .expectsToReceive( "an Order confirmation message" ) .withMetadata(Map.of( "Content-Type" , "application/json" )) .withContent( new PactDslJsonBody() .uuid( "orderId" ) .uuid( "paymentId" ) .decimalType( "amount" ) .stringType( "street" ) .stringType( "city" ) .stringType( "state" ) .stringType( "zip" ) .stringType( "country" )) .toPact(); } @Test @PactVerification (PROVIDER_ID) public void test() throws Exception { Assert.assertNotNull(message); } public void setMessage( byte [] messageContents) { message = messageContents; }  } 

它非常简单明了,没有添加样板。 测试用例是根据OrderConfirmed消息的JSON表示而设计的。 但是我们还只是半途而废, 货运 服务团队应该以某种方式将他们的期望回馈给订购服务,以便生产者跟踪谁以及如何消费OrderConfirmed消息。 Pact测试工具通过将每个JUnit测试用例中的pact文件(一组协议或pact)生成到“ target / pacs”文件夹中来解决此问题。 下面是运行OrderConfirmedConsumerTest测试套件后生成的Shipment Service-Order Service.json pact文件的示例

 { "consumer" : { "name" : "Shipment Service" }, "provider" : { "name" : "Order Service" }, "messages" : [ { "description" : "an Order confirmation message" , "metaData" : { "contentType" : "application/json" }, "contents" : { "zip" : "string" , "country" : "string" , "amount" : 100 , "orderId" : "e2490de5-5bd3-43d5-b7c4-526e33f71304" , "city" : "string" , "paymentId" : "e2490de5-5bd3-43d5-b7c4-526e33f71304" , "street" : "string" , "state" : "string" }, "providerStates" : [ { "name" : "default" } ], "matchingRules" : { "body" : { "$.orderId" : { "matchers" : [ { "match" : "regex" , "regex" : "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" } ], "combine" : "AND" }, "$.paymentId" : { "matchers" : [ { "match" : "regex" , "regex" : "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" } ], "combine" : "AND" }, "$.amount" : { "matchers" : [ { "match" : "decimal" } ], "combine" : "AND" }, "$.street" : { "matchers" : [ { "match" : "type" } ], "combine" : "AND" }, "$.city" : { "matchers" : [ { "match" : "type" } ], "combine" : "AND" }, "$.state" : { "matchers" : [ { "match" : "type" } ], "combine" : "AND" }, "$.zip" : { "matchers" : [ { "match" : "type" } ], "combine" : "AND" }, "$.country" : { "matchers" : [ { "match" : "type" } ], "combine" : "AND" } } } } ], "metadata" : { "pactSpecification" : { "version" : "3.0.0" }, "pact-jvm" : { "version" : "4.0.2" } }  } 

发货服务团队的下一步是与订单服务团队共享此协议文件,以便这些人可以在其测试套件中运行提供方的协议验证。

 @RunWith (PactRunner. class )  @Provider (OrderServicePactsTest.PROVIDER_ID)  @PactFolder ( "pacts" @PactFolder "pacts" )  public class OrderServicePactsTest { public static final String PROVIDER_ID = "Order Service" ; @TestTarget public final Target target = new AmqpTarget(); private ObjectMapper objectMapper;     @Before public void setUp() { objectMapper = new ObjectMapper(); } @State ( "default" ) public void toDefaultState() { }     @PactVerifyProvider ( "an Order confirmation message" ) public String verifyOrderConfirmed() throws JsonProcessingException { final OrderConfirmed order = new OrderConfirmed();         order.setOrderId(UUID.randomUUID()); order.setPaymentId(UUID.randomUUID()); order.setAmount( new BigDecimal( "102.33" )); order.setStreet( "1203 Westmisnter Blvrd" ); order.setCity( "Westminster" ); order.setCountry( "USA" ); order.setState( "MI" ); order.setZip( "92239" ); return objectMapper.writeValueAsString(order); }  } 

测试工具从@PactFolder中选取所有的pact文件,并针对@TestTarget进行测试,在这种情况下,我们要接线提供的AmqpTarget ,但是您可以轻松插入自己的特定目标。

基本上就是这样! 消费者( 装运服务 )在测试用例中表达了他们的期望,并以契约文件的形式与生产者( 订购服务 )共享了他们的期望。 生产者有自己的一组测试,以确保其模型符合消费者的观点。 双方可以继续独立发展,并相互信任,只要不谴责公约(希望,永远不要)。

公平地说, Pact并不是进行消费者驱动的合同测试的唯一选择,在即将发布的帖子中(已经开展工作),我们将讨论另一个出色的选择,即Spring Cloud Contract 。

直到今天,完整的项目资源都可以在Github上找到 。

翻译自: https://www.javacodegeeks.com/2019/11/tell-us-what-you-want-and-we-will-make-it-so-consumer-driven-contract-testing-for-messaging.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/340802.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

宝塔面板php降级,宝塔面板6.8.8降级到5.9.1的方案教程

有朋友问起,6.8版本用的不习惯,而且缺少5.9版本的nginx过滤器,而且6.8版本许多功能阉割的厉害:服务器状态中的 连接管理、进程管理 也都被阉割,5.9版本是可以在面板中查看服务器进程管理的,如图&#xff1a…

c++矩阵连乘的动态规划算法并输出_「Javascript算法设计」× 动态规划与回溯算法...

目录:分而治之算法动态规划回溯算法分而治之算法分而治之算法是算法设计的一种方式,它将一个问题分成多个和原问题相似的小问题,递归解决小问题,再将解决方式合并以解决原来的问题(例如快速排序,二分搜索等…

背包问题九讲_背包问题

背包问题九讲我发现背包问题既棘手又有趣。 我敢肯定,如果您正在访问此页面,您已经知道了问题说明,但是只是为了完成本章: 问题: 给定一个最大容量为W和N的背包,每个背包都有自己的值和重量,将…

随机森林的特征 是放回抽样么_机器学习超详细实践攻略(10):随机森林算法详解及小白都能看懂的调参指南...

一、什么是随机森林前面我们已经介绍了决策树的基本原理和使用。但是决策树有一个很大的缺陷:因为决策树会非常细致地划分样本,如果决策树分得太多细致,会导致其在训练集上出现过拟合,而如果决策树粗略地划分样本,又不…

http端口_PhpStorm 修改默认端口号63342

PhpStorm 修改默认端口号63342​blog.csdn.net关键词PhpStorm phpStorm phpstorm 修改默认端口号63342 8080 80步骤1.打开Settings2. Build, Execution, Deployment→Deployment3.点击添加,选择In place起一个名字(可以随便起)在Web server U…

rds mysql 磁盘空间,RDS MySQL 空间问题的原因和解决

other_size- 系统文件和临时文件使用空间data_size- 数据文件使用空间binlog_size- Binlog 文件占用空间注:获取实例诊断报告的步骤请参考如何访问RDS 实例诊断报告。2. 解决RDS 实例支持单独升级磁盘空间,升级磁盘空间是解决空间问题的有效方式之一。下…

微信小程序 全局变量异步函数_微信小程序【生命周期】

小程序分为应用、页面和组件三个部分,所以小程序的生命周期涉及以下应用的生命周期页面的生命周期组件的声明周期应用的生命周期对页面生命周期的影响应用的生命周期App() 函数用来注册一个小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。…

Java / Spring:如何快速生成整个数据库CRUD REST API

随着时间的流逝,Spring框架已成为Java中使用最广泛的Web开发框架之一,这一点已变得显而易见。 在接下来的十年之际,Spring最受欢迎的模块Spring Boot刚刚进行了重大更新。 新的Spring Boot版本“ 2.2.0”和年份“ 2020”几乎完美匹配。 因此…

python界面长什么样图片_python界面是什么样的

安装完Python,在命令行输入“python”之后,如果成功,会得到类似于下面的窗口:可以看到,结尾有3个>符号(>>>)。>>>被叫做Python命令提示符(prompt)&…

python表格控件_python GUI库图形界面开发之PyQt5表格控件QTableView详细使用方法与实例...

PyQt5表格控件QTableView简介 在通常情况下,一个应用需要和一批数据进行交互,然后以表格的形式输出这些信息,这时就需要用到QTableView类了,在QTableView中可以使用自定义的数据模型来显示内容,通过setModel来绑定数据…

Linux文件系统为,浅析Linux文件系统

原标题:浅析Linux文件系统一、文件系统层次分析由上而下主要分为用户层、VFS层、文件系统层、缓存层、块设备层、磁盘驱动层、磁盘物理层用户层最上面用户层就是我们日常使用的各种程序,需要的接口主要是文件的创建、删除、打开、关闭、写、读等。VFS层我…

求解出n以内所有能被5整除的正整数的乘积_所有最常见最经典的算法题都在这里了...

1、一群猴子排成一圈,按1,2,…,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去…,如此不停的进行下去,直到…

linux lvm 系统快照,系统运维|在 LVM中 录制逻辑卷快照并恢复(第三部分)

LVM快照是以空间换时间时间的方式制作的lvm卷副本。它只在lvm中工作,并只在源逻辑卷发生改变时占用快照卷的空间。如果源卷的变化达到1GB这么大,快照卷同样也会产生这样大的改变。因而,对于空间有效利用的最佳途径,就是总是进行小…

python语言变量随时声明_2. Go语言五种变量创建的方法

对于只有 Python 语言经验的朋友,也许会不太理解声明这个词,在 Python 中直接拿来就用,也不用声明类型啥的。 Go 语言是静态类型语言,由于编译时,编译器会检查变量的类型,所以要求所有的变量都要有明确的类…

会java需要多久能学会python_java好学吗?零基础学java要多久?

java好学吗?零基础学java要多久? 时间:2019-05-21 来源:华清远见 2019年3月,tiOBE 公布了编程语言排行榜,正如官方所说,本月的排名几乎没有任何有趣的变化,排名前十的依然是&…

jboss架构_检查Red Hat JBoss BRMS部署架构的规则和事件(第二部分)

jboss架构(文章来宾与北美红帽公司高级中间件顾问约翰赫洛克 ( John Hurlocker)合着) 在这周的技巧中,我们将放慢速度,并仔细研究可能的Red Hat JBoss BRMS部署体系结构。 在谈论部署体系结构时&#xff…

TestNG中的参数化– DataProvider和TestNG XML(带有示例)

测试自动化,或所谓的自动化测试,并不像听起来那样容易。 必须考虑所有可能的用户交互的所有排列和组合,并且在此基础上,您将必须创建测试脚本以通过多种浏览器和OS组合来验证Web应用程序。 这就是参数化在Selenium自动化测试中起关…

zbrush 添加纹理贴图_想学习3D游戏模型,3Dmax、MAYA和ZBrush都需要掌握吗?

想从事游戏行业的建模的话,模型和贴图的知识都得学,MAYA和3DMAX只能说是基本要学的,Zbrush能够提升个人价值,之后能给你建好的模型做出好看的贴图,才能算是一个游戏建模方面能干活的合格从业人员。新手入门的话&#x…

file.getpath_Java中File的getPath(),getCanonicalPath()和getAbsolutePath()之间的区别...

file.getpathFile API在Java中非常重要,因为它使文件系统可以访问Java程序。 尽管Java的文件API丰富,但是使用它们时仍需要了解很多细节。 关于文件路径的常见查询程序员之一是getPath() , getCanonicalPath()和getAbsolutePath()方法之间的区…

linux 在线帮助,linux获取在线帮助

Linux系统的帮助文档非常丰富。帮助手册提供命令的使用说明。比如你若是想了解ls命令的用法,只需运行:$ man ls帮助手册旨在提供基础知识和参考信息,有时会有一些实例和交叉索引,但是基本没有那种教程式的文档。帮助手册会按系统排…