Search code examples
javaspringasynchronousjmsjunit4

How to wait for @JMSListener annotated method to complete in JUnit


So I am trying to get some integration testing of JMS processing, Spring (v4.1.6) based code.

It's a very standard Spring setup with @JmsListener annotated method and a DefaultMessageListenerContainer with concurrency set to 1 and therefore allowing only 1 listening thread.

Now, I leveraged ActiveMQ's embedded broker not to rely on any external jms broker for the tests to run anywhere anytime (I should work in marketing).

So it all wires fine and then I have my JUnit test:

@Test
public void test() {
    sendSomeMessage();
    //how to wait here for the @JMSListener method to complete
    verify();
}

I send the message, but then I need to somehow wait for the @JMSListener annotated method to complete. How do I do this?


Solution

  • Well, I was hoping I can somehow hook into the Message Driven Pojos lifecycle to do this, but going through other SO questions about async code I came up with a solution based on CountDownLatch

    1. The @JMSListener annotaded method should call countDown() on a CountDownLatch after all the work is complete:

      @JmsListener(destination = "dest", containerFactory = "cf")
      public void processMessage(TextMessage message) throws JMSException {
          //do the actual processing
          actualProcessing(message);
          //if there's countDownLatch call the countdown.
          if(countDownLatch != null) {
              countDownLatch.countDown();
          }
      }
      
    2. In the testMethod

      @Test
      public void test() throws InterruptedException {
          //initialize the countDownLatch and set in on the processing class
          CountDownLatch countDownLatch = new CountDownLatch(1);
          messageProcessor.setCountDownLatch(countDownLatch);
          //sendthemessage
          sendSomeMessage();
          //wait for the processing method to call countdown()
          countDownLatch.await();
          verify();
      }
      

    The drawback of this solution is that you have to actually change your @JMSListener annotated method specifically for the integration test