spring_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 ,就不需要真正学习它了)。 这里有趣的部分是triggeredBysentTo块:基本上,这些轮廓是如何被生成的消息(或触发),并且其中它应该分别着陆(通道或队列名称)。 在这种情况下, 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”)帮助我们为测试用例选择正确的存根,并触发特定的消息传递合同验证流程。 “订单”值不是任意的,它应该与分配给合同规范的标签匹配,在我们的示例中,我们将其定义为:

 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 MavenGradle插件)。

 < 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 StreamSpring 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值