【问题标题】:Consumer-driven contract testing with Spring, JMS and ActiveMQ使用 Spring、JMS 和 ActiveMQ 进行消费者驱动的合同测试
【发布时间】:2019-07-24 13:35:15
【问题描述】:

我目前正在尝试在使用 ActiveMQ 消息进行通信的服务上下文中学习消费者驱动的合同测试。 Spring 提供了 Spring Cloud Contract Verifier Messaging 的文档 https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_spring_cloud_contract_verifier_messaging 但我无法使用我的设置(Spring Services 和 ActiveMQ)来遵循它。

我的问题是:

  • 对消息传递使用消费者驱动的合同测试是个好主意吗?
  • 最佳做法是什么?
  • 如果这是一个好主意,您是否有任何关于这方面的好教程,用于通过 JMS 和 ActiveMQ 进行通信的消费者驱动的合同测试 Spring 服务?

【问题讨论】:

    标签: activemq spring-cloud spring-jms producer-consumer spring-cloud-contract


    【解决方案1】:

    我设法为 JMS 和 ActiveMQ 创建了一个自定义 MessageVerifier,如下所示:

    package de.itemis.seatreservationservice;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import de.itemis.seatreservationservice.domain.ReservationRequest;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
    import org.springframework.context.annotation.Primary;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.messaging.support.GenericMessage;
    import org.springframework.stereotype.Component;
    
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.TextMessage;
    import java.io.IOException;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    
    @Component
    @Primary
    public class JmsMessageVerifier implements MessageVerifier {
    
        @Autowired
        JmsTemplate jmsTemplate;
    
        @Autowired
        ObjectMapper mapper;
    
        @Override
        public void send(Object message, String destination) {
            jmsTemplate.convertAndSend(destination, message, new ReplyToProcessor());
        }
    
        @Override
        public Object receive(String destination, long timeout, TimeUnit timeUnit) {
            jmsTemplate.setReceiveTimeout(timeout);
            return receiveMessage(destination);
        }
    
        @Override
        public Object receive(String destination) {
            return receiveMessage(destination);
        }
    
        @Override
        public void send(Object payload, Map headers, String destination) {
            ReservationRequest request = null;
            try {
                request = mapper.readValue((String) payload, ReservationRequest.class);
            } catch (IOException e) {
                e.printStackTrace();
            }
            jmsTemplate.convertAndSend(destination, request, new ReplyToProcessor());
        }
    
    
    
        private Object receiveMessage(String queueName) {
            Message message = jmsTemplate.receive(queueName);
            TextMessage textMessage = (TextMessage) message;
            try {
                return new GenericMessage<>(textMessage.getText());
            } catch (JMSException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    

    目前我在两个测试文件夹(生产者和消费者)中都需要它们。 通常我希望我的 Producer 中的 JmsMessageVerifier 将被打包在生成的存根 JAR 中,以便消费者合同测试使用这个 JmsMessageVerifier 而不是自己实现。

    你对这个Marcin Grzejszczak有什么想法?

    如果它是一个有用的功能,我会为此创建一个问题。

    这里是repository 两种服务:

    【讨论】:

    • 感谢托马索!所以你完全明白了!据我所知,您正在使用标准机制来发送和接收 JMS 消息。这意味着您需要例如ActiveMQ 在内存中运行,对吗?我并不是说那是错误的,但我想知道我们是否可以以某种方式解决这个问题(就像我们对 rabbitmq 所做的那样)。顺便说一句,您可以向 Spring Cloud Contract 的 master 分支提交 PR,我们可以在那里继续讨论吗?此外,我们正在更改文档,所以暂时不要添加它们;)
    【解决方案2】:

    但我无法使用我的设置(Spring Services 和 ActiveMQ)来遵循它。

    ActiveMQ 不支持开箱即用,您必须提供自己的 MessageVerifier 类型的 bean,在那里您将教框架如何发送和接收消息

    将消费者驱动的合同测试用于消息传递是个好主意吗?

    绝对!您可以遵循与 HTTP 相同的流程,但用于消息传递

    最佳做法是什么?

    这取决于 ;) 您可以按照标准做法进行 cdc,就好像它是基于 http 的通信一样。如果您想以您更关心主题/队列的方式抽象此类消息的生产者和消费者,您可以遵循此指南https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#_how_can_i_define_messaging_contracts_per_topic_not_per_producer,其中我们描述了如何定义每个主题而不是每个主题的消息传递合同制作人

    如果这是一个好主意,你有没有关于这方面的好教程,用于通过 JMS 和 ActiveMQ 进行通信的消费者驱动的合同测试 spring 服务?

    正如我之前所说,我们没有开箱即用的此类支持。但是,您可以使用 Spring Integration 或 Apache Camel 并通过它们与 ActiveMQ 进行通信。

    【讨论】:

    • 感谢您的快速回复。我实现了一个自定义 MessageVerifier,但现在我缺少其他两个注入到我生成的测试中的依赖项:@Inject ContractVerifierMessaging contractVerifierMessaging;@Inject ContractVerifierObjectMapper contractVerifierObjectMapper; 是否有自动配置这两个依赖项但仍使用自定义 MessageVerifier 的选项?
    • 绝对 - 它开箱即用。只需检查org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration。我们定义了缺失的 bean。
    • 我通过将我的 JmsMessageVerifier 声明为 @Primary 并保留 @AutoConfigureMessageVerifier 注释来避免这个问题
    • @MarcinGrzejszczak 将 Spring Cloud Contract 与 ActiveMQ 与我的服务当前使用的 spring-jms 设置一起使用的明智方法是什么?我是否需要开始使用 cloud stream/spring 集成/apache camel 而不是 spring-jms?
    • 您可以使用您在此答案中提到的或建议的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    • 1970-01-01
    • 2020-10-22
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    相关资源
    最近更新 更多