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