I have an application event listener which contains the function:
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//do some stuff
}
How can I write a unit test to simulate a ContextRefreshedEvent, like my jar being executed, and test that my onApplicationEvent function did what it's supposed to do?
Here is the smallest standalone example I can Think of.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.concurrent.LinkedBlockingQueue;
import static org.junit.Assert.assertEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RefreshTest.MyConfig.class})
public class RefreshTest {
@Autowired
private MyListener listener;
@Test
public void test() {
assertEquals("Refresh should be called once",1, listener.events.size());
}
public static class MyConfig {
@Bean
public MyListener listener() {
return new MyListener();
}
}
public static class MyListener implements ApplicationListener <ContextRefreshedEvent> {
// you don't really need a threadsafe collection in a test, as the test main thread is also loading the spring contest and calling the handler,
// but if you are inside an application, you should be aware of which thread is calling in case you want to read the result from another thread.
LinkedBlockingQueue<ContextRefreshedEvent> events = new LinkedBlockingQueue<ContextRefreshedEvent>();
public void onApplicationEvent(ContextRefreshedEvent event) {
events.add(event);
}
}
}
There is a difference between testing the code inside the handler and that the handler is called. Don't put code directly in the handler, but it in another bean, that is invoked from the handler, so you can test the logic without the handler (by calling it with an ContextRefreshedEvent
you created). A refresh event is sent when the context is refreshed (typically when it is loaded), so there is no need to test that. If it doesn't get called in your production code, you will usually notice immediately. Also the loading of context may be different between tests and production, so even if you write a test that shows the handler is called, there is no guarantee it will be called in production, unless you are running with exact same @Configuration
- Which I almost never do, since I often end up having different implementation of some configurations/bean using @Profile
for instance when I don't want my tests to use AWS Queues, and other external IO channels.