Spring amqp 如何为@RabbitListener注释编写集成测试?

Spring amqp 如何为@RabbitListener注释编写集成测试?,spring-amqp,spring-rabbit,Spring Amqp,Spring Rabbit,我的问题实际上是一个后续问题 在那里,它表示要包装“您的侦听器”,并传递一个倒计时锁存器,最终所有线程都将合并。如果我们手动创建并注入消息侦听器,但对于@RabbitListener注释,这个答案是有效的。。。我不知道如何通过倒计时。该框架在幕后自动神奇地创建消息侦听器 还有其他方法吗 使用@RabbitListener有点棘手,但最简单的方法是建议听众 使用“仅让您的测试用例向工厂添加建议” 建议是一个MethodInterceptor;调用将有2个参数;频道和(未转换的)消息。必须在创建容

我的问题实际上是一个后续问题

在那里,它表示要包装“您的侦听器”,并传递一个倒计时锁存器,最终所有线程都将合并。如果我们手动创建并注入消息侦听器,但对于@RabbitListener注释,这个答案是有效的。。。我不知道如何通过倒计时。该框架在幕后自动神奇地创建消息侦听器


还有其他方法吗

使用
@RabbitListener
有点棘手,但最简单的方法是建议听众

使用“仅让您的测试用例向工厂添加建议”

建议是一个
MethodInterceptor
;调用将有2个参数;频道和(未转换的)
消息
。必须在创建容器之前注入通知

或者,使用获取对容器的引用,稍后添加通知(但必须调用
initialize()
以强制应用新的通知)

另一种方法是使用一个简单的
BeanPostProcessor
,在将侦听器类注入容器之前代理它。这样,您将在任何转换后看到方法argumen;您还可以验证侦听器返回的任何结果(对于请求/应答场景)

如果您不熟悉这些技术,我可以试着找些时间为您快速制作一个示例

编辑


我发布了一个示例,向
EnableRabbitIntegrationTests
添加了一个示例。这将添加一个带有2个带注释的侦听器方法的侦听器bean,一个
BeanPostProcessor
,在将侦听器bean注入侦听器容器之前代理它。代理服务器中添加了一条
建议,当收到预期消息时,代理服务器会对锁定进行计数。

在@Gary Russell的帮助下,我得到了一个答案,并使用了以下解决方案

结论:我必须承认我对这个解决方案漠不关心(感觉像是一个黑客),但这是我唯一能做的事情,一旦你完成了最初的一次性设置并真正理解了“工作流程”,就不会那么痛苦了。基本上可以归结为定义(2)@bean并将它们添加到集成测试配置中

下面是示例解决方案,并附有解释。请随时对此解决方案提出改进建议

1。定义一个ProxyListenerBPP,它在spring初始化期间将侦听指定的clazz(即我们的测试类,其中包含@RabbitListener)和 注入下一步中定义的自定义CountDownLatchListenerInterceptor建议

import org.aopalliance.aop.Advice;
导入org.springframework.aop.framework.ProxyFactoryBean;
导入org.springframework.beans.BeansException;
导入org.springframework.beans.factory.BeanFactory;
导入org.springframework.beans.factory.BeanFactoryAware;
导入org.springframework.beans.factory.config.BeanPostProcessor;
导入org.springframework.core.Ordered;
导入org.springframework.core.PriorityOrdered;
/**
*实现BeanPostProcessorbean。。。在春季初始化期间,我们将
*侦听指定的clazz
*(即@RabbitListener注释类)和
*注入我们的定制CountDownLatchListenerInterceptor建议
*@作者sjacobs
*
*/
公共类ProxyListenerBPP实现BeanPostProcessor、BeanFactoryAware、Ordered、PriorityOrdered{
私人豆厂豆厂;
私人课堂;
公共静态最终字符串ADVICE\u BEAN\u NAME=“wasCalled”;
公共ProxyListenerBPP(类别分类){
this.clazz=clazz;
}
@凌驾
public void setBeanFactory(BeanFactory BeanFactory)抛出BeanException{
this.beanFactory=beanFactory;
}
@凌驾
公共对象后处理BeforeInitialization(对象bean、字符串beanName)抛出BeanException{
返回豆;
}
@凌驾
公共对象后处理初始化后(对象bean、字符串beanName)抛出BeansException{
if(clazz.isAssignableFrom(bean.getClass())){
ProxyFactoryBean pfb=新的ProxyFactoryBean();
setProxyTargetClass(true);//CGLIB,对于JDK代理为false(需要接口)
设置目标(bean);
addAdvice(this.beanFactory.getBean(ADVICE\u BEAN\u NAME,ADVICE.class));
返回pfb.getObject();
}
否则{
返回豆;
}
}
@凌驾
public int getOrder(){
返回Ordered.LOWEST_priority-1000;//就在@RabbitListener后处理器之前
}
2.创建MethodInterceptor advice impl,该impl将保存对CountDownLatch的引用。CountDownLatch需要在集成测试线程中以及@RabbitListener中的异步工作线程中被引用。因此,我们可以稍后在@RabbitListener异步线程已完成执行。无需轮询

import java.util.concurrent.CountDownLatch;
导入org.aopalliance.intercept.MethodInterceptor;
导入org.aopalliance.intercept.MethodInvocation;
/**
*AOP MethodInterceptor,它将单个CountDownLatch映射到一个方法并调用
*CountDownLatch.countDown()在方法完成执行之后。这背后的动机是什么
*用于集成测试Spring RabbitMq异步工作线程,以便能够合并
*异步“工作线程”完成任务后的集成测试线程。
*@作者sjacobs
*
*/
公共类CountDownLatchListenerInterceptor实现MethodInterceptor{
私有倒计时闩锁=新倒计时闩锁(1);
私有最终字符串方法名为InvokeCDL;
公共CountDownLatchListenerInterceptor(字符串方法名){