2. JMS + IBM MQ + Tests

2. JMS + IBM MQ + Tests

Нужно написать интеграционный тест для тестирования обработки входящих в топик сообщений. Для этого нужно будет настроить тестовый контекст таким образом, чтобы поднимался встроенный JMS-сервер, через который осуществлялось бы взаимодействие.

Буду рассматривать приложение, описанное в первой статье: https://blog.knasys.ru/1-jms-ibm-mq-pub-sub/

Я не нашел информации о том можно ли встроить IBM MQ в приложение, поэтому встраивать будем ActiveMQ (он так умеет точно =) ), а поскольку он тоже является реализацией JMS, то проблем быть не должно.

Для начала нам понадобится зависимость:

<dependency>
	<groupId>org.apache.activemq</groupId>
	<artifactId>activemq-broker</artifactId>
	<scope>test</scope>
</dependency>

Далее, для тестового профиля, нам следует отключить бины внутри основной конфигурации, которые настраивают связь с сервером IBM MQ, т.е. над бинами ru.knastnt.springjmsibmmq.config.IbmMqConfiguration.MQConfigurationProperties и
ru.knastnt.springjmsibmmq.config.IbmMqConfiguration.MQConnectionFactory поставить аннотацию
@Profile(«!test»)

Теперь создадим родительский класс для всех интеграционнах тестов, в котором опишем все требования к контексту.

Сразу после добавления зависимости, в приложении будет стартовать встроенный брокер сообщений Acrive MQ, осталось только добавить ConnectionFactory для создания подключения к нему (называться он должен так же как и ConnectionFactory для IBM MQ, ведь мы его таким образом подменяем). Также создадим JmsTemplate, чтобы иметь возможность отправлять сообщения в топик:

package ru.knastnt.springjmsibmmq;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.test.context.ActiveProfiles;

import javax.jms.ConnectionFactory;

@ActiveProfiles("test") //Говорим что в интеграционных тестах профиль будет test
@SpringBootTest
public class BaseIT {
    @Configuration
    public static class TestConfig {
        @Bean //Подключаемся к уже встроенному локальному JMS-серверу, и отключаем сохраняемость сообщений
        public ConnectionFactory connectionFactory() {
            return new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");
        }

        @Bean //Создаём темплейт, чтобы слать сообщения в топик
        public JmsTemplate topicJmsTemplate(ConnectionFactory connectionFactory){
            JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
            jmsTemplate.setPubSubDomain(true);//говорим что будем работать в режиме Publisher/Subscriber
            return jmsTemplate;
        }

    }

    @Autowired
    private JmsTemplate topicJmsTemplate;

    @Value("${client.publ.jms.topic-name}")
    private String topicName;

    //Метод для простой отправки сообщения в топик
    public void writeInTopic(String message) {
        topicJmsTemplate.convertAndSend(topicName, message);
    }
}

Стоит обратить внимание, что мы не переопределяли бин
ru.knastnt.springjmsibmmq.config.IbmMqConfiguration.DefaultJmsListenerContainerFactory, и он по-прежнему работает в нашей основной конфикурации и даёт возможность слушать нужный топик при помощи @JmsListener в классе Receiver.

Осталось написать сам тест. Надо обметить, что получение сообения является асинхронной задачей, поэтому для контроля вызова буду использовать таймаут. Для наглядности, напишу 1000 итераций =)

package ru.knastnt.springjmsibmmq.mq;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.messaging.Message;
import ru.knastnt.springjmsibmmq.BaseIT;

import static org.junit.jupiter.api.Assertions.*;

class ReceiverIT extends BaseIT {
    @SpyBean(Receiver.class)
    private Receiver receiver;
    @Test
    void test() {
        for (int i = 0; i < 1000; i++) {
            writeInTopic("hi!"+i);
            ArgumentCaptor<Message> ac = ArgumentCaptor.forClass(Message.class);
            Mockito.verify(receiver, Mockito.timeout(10000)).receiveMessage(ac.capture());
            assertEquals("hi!"+i, ac.getValue().getPayload());
            Mockito.clearInvocations(receiver);
        }
    }
}

Исходники можно глянуть здесь

(Просмотрено 883 раз, 1 раз за сегодня)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *