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?
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
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();
}
}
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