消费者驱动的契约测试

相当早以前,我们从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

消费者驱动的契约测试

消费者驱动的契约测试_告诉我们您想要什么,我们将做到:消费者驱动的合同测试消息传递...相关推荐

  1. mysql小结果集驱动大结果集_具体优化查询语句的指导原则小结果集驱动大结果集避免子查询...

    原标题:具体优化查询语句的指导原则小结果集驱动大结果集避免子查询 具体优化Query语句的指导原则 (1)多使用Profile:(2)永远用小结果集驱动大的结果集:(3)尽可能在索引中完成排序:(4) ...

  2. python文档测试_【Python入门】19.调试器pdb、单元测试unittest和文档测试doctest

    笔记更新于2019年12月4日, 摘要:各种调试方法介绍assert.logging.调试器pdb:单元测试unittest的编写方法.如何运行单元测试:文档测试doctest的编写 写在前面:为了更 ...

  3. fpu测试_正点原子STM32F4/F7水星开发板资料连载第五十章 FPU 测试实验

    1)实验平台:正点原子水星 STM32F4/F7 开发板 2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 3)全套实验源码+手册+视频下载 ...

  4. 学python要有多少英语词汇量测试_非常适合新手的一个Python爬虫项目: 打造一个英文词汇量测试脚本!...

    最近朋友在苦学英文,但是又不知道自己学的怎么样了,直到有一天,他找到了扇贝网,里面有个"评估你的单词量"功能非常的好,就推荐给我了! 今天我们就用python做一个小的爬虫,然后自 ...

  5. python英语词汇量测试_非常适合新手的一个Python爬虫项目: 打造一个英文词汇量测试脚本!...

    最近朋友在苦学英文,但是又不知道自己学的怎么样了,直到有一天,他找到了扇贝网,里面有个"评估你的单词量"功能非常的好,就推荐给我了! 今天我们就用python做一个小的爬虫,然后自 ...

  6. fpga驱动rgb液晶屏_用FPGA设计LCD 转 VGA 其实vga和lcd驱动 非常类似

    这个东西其实是在上一个冬天就做完了,而且似乎已经产业化了,当时是为一位朋友做的,这个朋友再卖给产业化的人,就像流于俗套的故事一样,这个朋友拿到了钱,不过不像项目开始时说的那样与我有关.想想多年前一起吃 ...

  7. java + testng wsdl 测试_在测试中使用XPATH断言的策略

    ***************************************************************** 在这门课里你将学到Web Services(SOAP WebServ ...

  8. 07 契约测试:如何进行消费者驱动的契约测试?

    上一课时,我讲到了微服务架构下的组件测试,它是针对单个微服务的验收测试,虽然保障了单个微服务功能的正确性,但要想保障微服务间交互功能的正确性,就需要进行契约测试. 契约测试产生的背景 在介绍契约测试之 ...

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

    相当早以前,我们从REST(ful) Web API的角度讨论了消费者驱动的合同测试 ,尤其是将其投射到Java( JAX-RS 2.0规范)的角度. 可以公平地说,至少在公共API方面, REST仍 ...

最新文章

  1. python计时器精度_在python中获得更精确的计时器
  2. Linux 终端訪问 FTP 及 上传下载 文件
  3. 数据结构学习笔记(2)
  4. 原来国家的名字可以如此浪漫!(ZZ)
  5. 基于E18-2G4U04B的ZigBee3.0无线数据抓包安装方法
  6. Windows:将cmd命令行添加到右键中方法
  7. [转]关于flash中图片(jpg\png\gif)旋转后锯齿(模糊)问题
  8. objective-c 2.0编程语言,Objective-C 2.0编程快速上手 EXE版[12MB]
  9. java 求高精度幂_POJ 1001 求高精度幂【JAVA】
  10. [Linux] 获取Shell脚本自身所在位置的绝对路径;
  11. 计算机基础知识试题分值,计算机考试题分值分布.doc
  12. 海康威视摄像头使用:iVMS-4200 VS客户端
  13. cad vba 打开文件对话框_CADvba开发手册.doc
  14. linux就该这么学
  15. PHP一句话木马后门
  16. Unix平台下的常用命令技巧之资源与性能
  17. python浮点数加整数_Python中整数和浮点数运算
  18. Openpose2d转换3d姿态识别
  19. Windows Mobile 5.0 认知篇
  20. 用JS写小鸟飞行的游戏

热门文章

  1. AcWing 1303. 斐波那契前 n 项和
  2. 牛客题霸 [ 判断一棵二叉树是否为搜索二叉树和完全二叉树] C++题解/答案
  3. 「ROI 2017 Day 2」反物质(单调队列优化dp)
  4. CSP2019洛谷P5666:树的重心
  5. AT2376-[AGC014D]Black and White Tree【结论,博弈论】
  6. P7599-[APIO2021]雨林跳跃【二分,倍增,ST表】
  7. P2633-Count on a tree【主席树,LCA】
  8. jzoj3853-帮助Bsny【dp】
  9. P1613-跑路【Floyd,倍增】
  10. 动态规划训练14 [Max Sum Plus Plus HDU - 1024 ]