使用 Spring、JMS 和 ActiveMQ 进行消费者驱动的合同测试

Consumer-driven contract testing with Spring, JMS and ActiveMQ

我目前正在尝试在使用 ActiveMQ 消息进行通信的服务环境中学习消费者驱动的合同测试。 Spring 为 Spring Cloud Contract Verifier Messaging 提供文档 https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_spring_cloud_contract_verifier_messaging 但我无法按照我的设置(Spring 服务和 ActiveMQ)进行操作。

我的问题是:

but I was not able to follow it with the setting I have ( Spring Services and ActiveMQ ).

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

Is it a good idea to use consumer-driven contract testing for messaging ?

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

What are the best practices ?

这取决于 ;) 您可以按照标准做法进行 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,我们在其中描述了如何为每个主题定义消息传递合同以及不是每个制作人

If its a good idea, do you have any good tutorials on this for consumer-driven contract testing spring services that communicate via JMS and ActiveMQ ?

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

我设法为 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;
        }
    }
}

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

你对此有何看法Marcin Grzejszczak

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

这是包含两种服务的 repository