junit spring jms监听器 [英] junit spring jms listener
问题描述
我想对下面的简单jms侦听器代码进行单元测试
I want to unit test a simple jms listener code below
@Component
public class NotificationReader {
@JmsListener(destination = "myAppQ")
public void receiveMessage(NotificationMessage notificationMessage) {
System.out.println("Received <" + notificationMessage.getStaffNumber() + ">");
}
}
我从junit使用jmsTemplate将消息发送到Active MQ.
From the junit, I am using jmsTemplate to pump the message into Active MQ.
我想测试是否调用了jms侦听器.
I want to test if the jms listener got invoked.
I saw few solutions ( using counters ) like How to wait for @JMSListener annotated method to complete in JUnit, which actually changes the listener code just for testing purpose which I dont want to do.
还有其他选择吗?
尝试按照答案中的建议进行配置.
Tried with configuration as suggested in the answer .
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestNotificationReader {
@Autowired
JmsTemplate jmsTemplate;
@Value("${outbound.endpoint}")
private String destination;
@Test
public void contextLoads() {
}
@Test
public void testPutToQ() {
NotificationMessage notificationMessage = new NotificationMessage();
notificationMessage.setStaffNumber("100");
notificationMessage.setWorkflowType("TYPE");
notificationMessage.setWorkflowId("100");
notificationMessage.setWorkflowDescription("Test From Queue");
jmsTemplate.convertAndSend(destination, notificationMessage);
jmsTemplate.setReceiveTimeout(10000);
try {
TestConfig.latch.await(10, TimeUnit.SECONDS);
NotificationMessage temp = (NotificationMessage) TestConfig.received;
System.out.println(" temp.getStaffNumber() " + temp.getStaffNumber());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Configuration
public static class TestConfig {
private static final CountDownLatch latch = new CountDownLatch(1);
private static Object received;
@Bean
public static BeanPostProcessor listenerWrapper() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof NotificationReader) {
MethodInterceptor interceptor = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = invocation.proceed();
if (invocation.getMethod().getName().equals("receiveMessage")) {
received = invocation.getArguments()[0];
latch.countDown();
}
return result;
}
};
if (AopUtils.isAopProxy(bean)) {
((Advised) bean).addAdvice(interceptor);
return bean;
} else {
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.addAdvice(interceptor);
return proxyFactory.getProxy();
}
} else {
return bean;
}
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
return bean;
}
};
}
}
}
一旦添加了testConfig,JMSTempate自动装配就会失败
Once I add the testConfig , the JMSTempate autowiring fails
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.jms.core.JmsTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
推荐答案
将侦听器bean封装在代理中(用于测试用例),并使用闩锁并验证接收到的对象是否符合您的期望...
Wrap your listener bean in a proxy (for the test case) and use a latch and verify that the object received is what you expected...
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { So48033124Application.class, So48033124ApplicationTests.TestConfig.class })
public class So48033124ApplicationTests {
@Autowired
private JmsTemplate template;
@Test
public void test() throws Exception {
Foo foo = new Foo("bar");
this.template.convertAndSend("foo", foo);
assertThat(TestConfig.latch.await(10, TimeUnit.SECONDS)).isTrue();
assertThat(TestConfig.received).isEqualTo(foo);
}
@Configuration
public static class TestConfig {
private static final CountDownLatch latch = new CountDownLatch(1);
private static Object received;
@Bean
public static BeanPostProcessor listenerWrapper() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyListener) {
MethodInterceptor interceptor = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = invocation.proceed();
if (invocation.getMethod().getName().equals("listen")) {
received = invocation.getArguments()[0];
latch.countDown();
}
return result;
}
};
if (AopUtils.isAopProxy(bean)) {
((Advised) bean).addAdvice(interceptor);
return bean;
}
else {
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.addAdvice(interceptor);
return proxyFactory.getProxy();
}
}
else {
return bean;
}
}
};
}
}
}
编辑
以上内容基于使用Java 8的Spring Framework 5或更高版本,并提供了两个BeanPostProcessor
方法的默认实现.
The above is based on Spring Framework 5 or later which uses Java 8 and provides default implementations for both BeanPostProcessor
methods.
如果您使用的是较早版本的Spring,则还需要
If you are using an earlier version of Spring you will also need
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
BPP也应为static
.
这篇关于junit spring jms监听器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!