Reputation: 2924
I am writing unit/integration test to check whether the JMS listener using IBM MQ is getting called correctly. There are two listeners in my IncomingDataListener. They are for two types of data comming in the same queue, processed by MyDataProcessorService and MyOtherDataProcessorService.
As can be seen below I have mocked the two services MyDataProcessorService and MyOtherDataProcessorService.
But I am not using JmsTemplate to send the message to my queue, to test whether the correct method is being called.
Instead I am reading the xml file directly by directly calling the recieveMessage() method and checking the correct data processor service is being called or not.
Do let me know whether I should rather be sending message using the JmsTemplate to the queue, rather than going ahead with this approach of directly calling the reciever?
@RunWith(SpringRunner.class)
@Import({IncomingDataListener.class, DefaultJmsListenerContainerFactory.class})
@ContextConfiguration(classes = JmsConfig.class)
@PropertySource("classpath:config/application-test.properties")
public class IncomingDataListenerTest {
@Autowired
private IncomingDataListener incomingDataListener;
@MockBean
private MyDataProcessorService myDataProcessorService;
@MockBean
private MyOtherDataProcessorService myOtherDataProcessorService;
private String myDataFileString;
@PostConstruct
public void setup() throws IOException {
myDataFileString = XmlUtils.readFile("FileHavingXMLData.xml");
}
@Test
public void testProcessMyData() throws StaticDataValidationException {
incomingDataListener.receiveMessage(myDataFileString);// Directly I am calling the IncomingDataListener classes recieveMessage method, is it right or wrong??
verify(myDataProcessorService, times(1)).process(any());
verify(myOtherDataProcessorService, times(0)).processOther(any());
}
}
Here is the config class, initially I thought of creating a JmsTemplate to send the message to the queue and then test at the listener side whether the correct processor is getting called!!
@Configuration
@PropertySource("classpath:config/application-test.properties")
@Slf4j
public class JmsConfig {
@Value("${mq.jms.host}")
private String host;
@Value("${mq.jms.port}")
private Integer port;
@Value("${mq.jms.queue.manager}")
private String queueManager;
@Value("${mq.jms.channel}")
private String channel;
@Value("${mq.inbound.queue}")
private String queue;
@Value("${mq.timeout}")
private Long timeout;
@Bean
public MQQueueConnectionFactory getConnectionFactory() {
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
try {
mqQueueConnectionFactory.setHostName(host);
mqQueueConnectionFactory.setQueueManager(queueManager);
mqQueueConnectionFactory.setChannel(channel);
} catch (JMSException e){
log.debug("Error creating Connection Factory");
}
return mqQueueConnectionFactory;
}
@Bean
public JmsTemplate jmsTemplateFactory(MQQueueConnectionFactory mqQueueConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate(mqQueueConnectionFactory);
return jmsTemplate;
}
@Bean
public JmsListenerContainerFactory queueContainer(MQQueueConnectionFactory mqQueueConnectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(mqQueueConnectionFactory);
return factory;
}
}
To my knowledge I have done all the things required, but I am getting this exception as Listed below.
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.postProcessFields(MockitoTestExecutionListener.java:95)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.injectFields(MockitoTestExecutionListener.java:79)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.prepareTestInstance(MockitoTestExecutionListener.java:54)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'jmsListenerContainerFactory' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:814)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1282)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.jms.config.JmsListenerEndpointRegistrar.resolveContainerFactory(JmsListenerEndpointRegistrar.java:159)
at org.springframework.jms.config.JmsListenerEndpointRegistrar.registerAllEndpoints(JmsListenerEndpointRegistrar.java:143)
at org.springframework.jms.config.JmsListenerEndpointRegistrar.afterPropertiesSet(JmsListenerEndpointRegistrar.java:135)
at org.springframework.jms.annotation.JmsListenerAnnotationBeanPostProcessor.afterSingletonsInstantiated(JmsListenerAnnotationBeanPostProcessor.java:210)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:912)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:128)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:275)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:243)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
... 25 more
Please tell me how to come out of this conundrum.
Upvotes: 1
Views: 5006
Reputation: 469
I think that one of following should work for you
You can learn more about how spring names beans and wires them to classes from the following sources:
Upvotes: 1
Reputation: 174729
Your factory has a non-standard bean name; the default is jmsListenerContainerFactory
; if you name it something else, you must specify the bean name on the @JmsListener
annotation.
Either
@Bean
public JmsListenerContainerFactory jmsListenerContainerFactory(MQQueueConnectionFactory mqQueueConnectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(mqQueueConnectionFactory);
return factory;
}
or
@Bean("jmsListenerContainerFactory")
public JmsListenerContainerFactory queueContainer(MQQueueConnectionFactory mqQueueConnectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(mqQueueConnectionFactory);
return factory;
}
/**
* The bean name of the {@link org.springframework.jms.config.JmsListenerContainerFactory}
* to use to create the message listener container responsible for serving this endpoint.
* <p>If not specified, the default container factory is used, if any.
*/
String containerFactory() default "";
Upvotes: 3