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?
In order to avoid having to change your actual @JmsListener method, you could try and use AOP in your test...
First create an aspect class like this:
Then add it in your application context configuration you're using for testing, like this:
If everything goes as planned, the JmsListenerInterceptor will count down and you don't have to change your actual code.
IMPORTANT: I just found out that using AOP and Mockito to verify if certain methods in your @JmsListener have been called is a bad combination. The reason seems to be the extra wrapping into CGLib classes resulting in the wrong/actual target instance to be invoked instead of the Mockito proxy.
In my test, I have an @Autowired, @InjectMocks Listener object and a @Mock Facade object for which I want to verify that a certain method has been called.
With AOP:
Without AOP:
This goes to show that you'll need to watch out using AOP the way I tried to, as you might end up with different instances in both Threads...
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 callcountDown()
on a CountDownLatch after all the work is complete:In the testMethod
The drawback of this solution is that you have to actually change your
@JMSListener
annotated method specifically for the integration testIf you would add logging to the @JmsListener annotated method, you could do something like this in the test class