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); } } } |
Исходники можно глянуть здесь