Writing Unit Tests to test JMS Queue listener code with ActiveMQ

During my GSoC project for OpenNMS i did some work with JMS and wanted to write test classes to make sure that my code was working well. In this article i will try to explain how you can use ActiveMQ to write test cases for your JMS code. This is very handy when your code has a part that listens to a JMS queue.

Apache ActiveMQ 

Apache ActiveMQ is a extremely popular and very powerful open source messaging and Integration Patterns server. You can check it out here. The part we will be using to run our test classes is the embedded broker that is provided by ActiveMQ. This allows you to create a temporary broker for test purposes to create a JMS queue in our case. If you want to learn more about the embedded broker check out this article. The easiet way to create a embedded broker is through the following code line. This will automatically create a embedded broker.
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");

Code to be tested

Before we take a look at the test code lets take a look at the code that we are trying to test. here the purpose of code is to listen to a given JMS Queue and do some processing on the received data. to allow smooth operation of the listener code we will need to create 3 classes.

The Server class this is the main class that will listen to the Queue. below is the code snippet that will start the JMS Queue connection.
public void startServer(){
        try{
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");

            // create a queue connection
            QueueConnection queueConn = (QueueConnection) connectionFactory.createConnection();

            // create a queue session
            QueueSession queueSession = queueConn.createQueueSession(false,
                                                                     Session.DUPS_OK_ACKNOWLEDGE);

            Destination destination = queueSession.createQueue("TESTQUEUE");


            // create a queue receiver
            MessageConsumer consumer = queueSession.createConsumer(destination);

            // set an asynchronous message listener
            MeasurementListner measurementListner = new MeasurementListner();
            consumer.setMessageListener(measurementListner);

            // set an asynchronous exception listener on the connection
            MeasurementExceptionListener measurementExceptionListener = new MeasurementExceptionListener();
            queueConn.setExceptionListener(measurementExceptionListener);
            queueConn.start();

        }catch(Exception e){
            logger.error("JMS Exception",e.getMessage());
        }
To make sure that the server is running continually you can use a wait method as given below and call it just after calling the startServer() method. If you only want to run the server for a limited time you can use a Thread.sleep(timeinmillies).
 synchronized void waitForever()
    {   
        while (true) {
            try {
                wait();
            } catch (InterruptedException ex) { }


        }
    }
The other 2 classes that you will need is a class that implements the MessageListener interface and ExceptionListener interface the two classes MeasurementListner and MeasurementExceptionListener are those two classes, the onMessage(Message message) method is called when a message is received from the JMS Queue. So we want to test if the code actually gets messages from the defined queue that why we need the ActiveMQ embedded broker.

Writing the Test code
 public class ListnerTest {

    private String jmsQueue = "TESTQUEUE";
    private String url = "vm://localhost?broker.persistent=false";
    @Test
    public void testMeasurment(){

        try {
            .........
            String string = new String("Hello");
           
            sendMessage(string);

            Server server = new Server();
            server.main(null);
            ........
            
        } catch (MessageConversionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 

    }
   

    private void sendMessage(Object obj){
        try{
            
            SimpleMessageConverter smConverter = new SimpleMessageConverter();
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
            Message message;

            
            QueueConnection queueConn = (QueueConnection) connectionFactory.createConnection();
            queueConn.start();

            QueueSession queueSession = queueConn.createQueueSession(false,
                                                                     Session.DUPS_OK_ACKNOWLEDGE);

            Destination destination = queueSession.createQueue(jmsQueue);

            MessageProducer queueSender = queueSession.createProducer(destination);
            queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            
            message = smConverter.toMessage(obj, queueSession);
            queueSender.send(message);
            
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

}

The test code simple creates a String and writes into the JMS Queue created using the embedded broker of ActiveMQ. i am calling the main method of the server since the startServer() call and wait call is made in the main method. If you got everything running you should be able to get a nice unit test running for your project. I hope this was helpful to anyone trying to do this. please leave a comment if you need any clarification i can help out if possible.


Popular posts from this blog

How to set up a Apache Spark cluster in your local machine

Apache Hadoop MapReduce - Detailed word count example from scratch