消费者驱动的契约测试_告诉我们您想要什么,我们将做到:消费者驱动的合同测试消息传递...
消費者驅動的契約測試
相當早以前,我們從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
消費者驅動的契約測試
總結
以上是生活随笔為你收集整理的消费者驱动的契约测试_告诉我们您想要什么,我们将做到:消费者驱动的合同测试消息传递...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: flash电脑版官方下载(flash中文
- 下一篇: 解决u盘无法弹出的操作方法(解决u盘无法