diff --git a/spring-jms/pom.xml b/spring-jms/pom.xml index 09bf854221..ab202402f3 100644 --- a/spring-jms/pom.xml +++ b/spring-jms/pom.xml @@ -41,6 +41,25 @@ ${spring-boot-test.version} test + + + org.mockito + mockito-core + 4.6.1 + test + + + org.apache.activemq.tooling + activemq-junit + 5.16.5 + test + + + org.testcontainers + testcontainers + 1.17.3 + test + diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java new file mode 100644 index 0000000000..0a89d422b4 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.spring.jms.testing; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ComponentScan; + +@ComponentScan +public class JmsApplication { + + public static void main(String[] args) { + ApplicationContext context = new AnnotationConfigApplicationContext(JmsApplication.class); + } +} diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java new file mode 100644 index 0000000000..92abb32861 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/JmsConfig.java @@ -0,0 +1,34 @@ +package com.baeldung.spring.jms.testing; + +import javax.jms.ConnectionFactory; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.annotation.EnableJms; +import org.springframework.jms.config.DefaultJmsListenerContainerFactory; +import org.springframework.jms.config.JmsListenerContainerFactory; +import org.springframework.jms.core.JmsTemplate; + +@Configuration +@EnableJms +public class JmsConfig { + + @Bean + public JmsListenerContainerFactory jmsListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + return factory; + } + + @Bean + public ConnectionFactory connectionFactory() { + return new ActiveMQConnectionFactory("tcp://localhost:61616"); + } + + @Bean + public JmsTemplate jmsTemplate() { + return new JmsTemplate(connectionFactory()); + } + +} diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java new file mode 100644 index 0000000000..f66a99c876 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageListener.java @@ -0,0 +1,20 @@ +package com.baeldung.spring.jms.testing; + +import javax.jms.JMSException; +import javax.jms.TextMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jms.annotation.JmsListener; +import org.springframework.stereotype.Component; + +@Component +public class MessageListener { + + private static final Logger logger = LoggerFactory.getLogger(MessageListener.class); + + @JmsListener(destination = "queue-1") + public void sampleJmsListenerMethod(TextMessage message) throws JMSException { + logger.info("JMS listener received text message: {}", message.getText()); + } +} diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java new file mode 100644 index 0000000000..6cb199b0e9 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/testing/MessageSender.java @@ -0,0 +1,21 @@ +package com.baeldung.spring.jms.testing; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.stereotype.Component; + +@Component +public class MessageSender { + + @Autowired + private JmsTemplate jmsTemplate; + + private static final Logger logger = LoggerFactory.getLogger(MessageSender.class); + + public void sendTextMessage(String destination, String message) { + logger.info("Sending message to {} destination with text {}", destination, message); + jmsTemplate.send(destination, s -> s.createTextMessage(message)); + } +} diff --git a/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java b/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java new file mode 100644 index 0000000000..6644ee50ac --- /dev/null +++ b/spring-jms/src/test/java/com/baeldung/spring/jms/testing/EmbeddedActiveMqIntegrationTest.java @@ -0,0 +1,91 @@ +package com.baeldung.spring.jms.testing; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.junit.EmbeddedActiveMQBroker; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.annotation.EnableJms; +import org.springframework.jms.config.DefaultJmsListenerContainerFactory; +import org.springframework.jms.config.JmsListenerContainerFactory; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.spring.jms.testing.EmbeddedActiveMqIntegrationTest.TestConfiguration; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { TestConfiguration.class }) +public class EmbeddedActiveMqIntegrationTest { + + @ClassRule + public static EmbeddedActiveMQBroker embeddedBroker = new EmbeddedActiveMQBroker(); + + @SpyBean + private MessageListener messageListener; + + @SpyBean + private MessageSender messageSender; + + @Test + public void whenListening_thenReceivingCorrectMessage() throws JMSException { + String queueName = "queue-1"; + String messageText = "Test message"; + + embeddedBroker.pushMessage(queueName, messageText); + assertEquals(1, embeddedBroker.getMessageCount(queueName)); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(TextMessage.class); + + Mockito.verify(messageListener, Mockito.timeout(100)) + .sampleJmsListenerMethod(messageCaptor.capture()); + + TextMessage receivedMessage = messageCaptor.getValue(); + assertEquals(messageText, receivedMessage.getText()); + } + + @Test + public void whenSendingMessage_thenCorrectQueueAndMessageText() throws JMSException { + String queueName = "queue-2"; + String messageText = "Test message"; + + messageSender.sendTextMessage(queueName, messageText); + + assertEquals(1, embeddedBroker.getMessageCount(queueName)); + TextMessage sentMessage = embeddedBroker.peekTextMessage(queueName); + assertEquals(messageText, sentMessage.getText()); + } + + @Configuration + @EnableJms + static class TestConfiguration { + @Bean + public JmsListenerContainerFactory jmsListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + return factory; + } + + @Bean + public ConnectionFactory connectionFactory() { + return new ActiveMQConnectionFactory(embeddedBroker.getVmURL()); + } + + @Bean + public JmsTemplate jmsTemplate() { + return new JmsTemplate(connectionFactory()); + } + } + +} diff --git a/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqIntegrationTest.java b/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqIntegrationTest.java new file mode 100644 index 0000000000..d117b90423 --- /dev/null +++ b/spring-jms/src/test/java/com/baeldung/spring/jms/testing/TestContainersActiveMqIntegrationTest.java @@ -0,0 +1,101 @@ +package com.baeldung.spring.jms.testing; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.assertj.core.api.Assertions; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.annotation.EnableJms; +import org.springframework.jms.config.DefaultJmsListenerContainerFactory; +import org.springframework.jms.config.JmsListenerContainerFactory; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.spring.jms.testing.TestContainersActiveMqIntegrationTest.TestConfiguration; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { TestConfiguration.class, MessageSender.class }) +public class TestContainersActiveMqIntegrationTest { + + @ClassRule + public static GenericContainer activeMqContainer = new GenericContainer<>(DockerImageName.parse("rmohr/activemq:5.14.3")).withExposedPorts(61616); + + @SpyBean + private MessageListener messageListener; + + @Autowired + private MessageSender messageSender; + + @Autowired + private JmsTemplate jmsTemplate; + + @Test + public void whenListening_thenReceivingCorrectMessage() throws JMSException { + String queueName = "queue-1"; + String messageText = "Test message"; + + jmsTemplate.send(queueName, s -> s.createTextMessage(messageText)); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(TextMessage.class); + + Mockito.verify(messageListener, Mockito.timeout(100)) + .sampleJmsListenerMethod(messageCaptor.capture()); + + TextMessage receivedMessage = messageCaptor.getValue(); + assertEquals(messageText, receivedMessage.getText()); + } + + @Test + public void whenSendingMessage_thenCorrectQueueAndMessageText() throws JMSException { + String queueName = "queue-2"; + String messageText = "Test message"; + + messageSender.sendTextMessage(queueName, messageText); + + Message sentMessage = jmsTemplate.receive(queueName); + Assertions.assertThat(sentMessage) + .isInstanceOf(TextMessage.class); + + assertEquals(messageText, ((TextMessage) sentMessage).getText()); + } + + @Configuration + @EnableJms + static class TestConfiguration { + @Bean + public JmsListenerContainerFactory jmsListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + return factory; + } + + @Bean + public ConnectionFactory connectionFactory() { + String brokerUrlFormat = "tcp://%s:%d"; + String brokerUrl = String.format(brokerUrlFormat, activeMqContainer.getHost(), activeMqContainer.getFirstMappedPort()); + return new ActiveMQConnectionFactory(brokerUrl); + } + + @Bean + public JmsTemplate jmsTemplate() { + return new JmsTemplate(connectionFactory()); + } + } + +}