如何等待@JMSListener注释方法在JUnit中完成

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何等待@JMSListener注释方法在JUnit中完成相关的知识,希望对你有一定的参考价值。

所以我试图对基于Spring(v4.1.6)的JMS处理代码进行一些集成测试。

这是一个非常标准的Spring设置,使用@JmsListener注释方法和DefaultMessageListenerContainerconcurrency设置为1,因此只允许1个监听线程。

现在,我利用ActiveMQ的嵌入式代理不依赖任何外部jms代理来随时随地运行测试(我应该在市场营销中工作)。

所以这一切都很好,然后我有我的JUnit测试:

@Test
public void test() {
    sendSomeMessage();
    //how to wait here for the @JMSListener method to complete
    verify();
}

我发送消息,但后来我需要以某种方式等待@JMSListener注释方法完成。我该怎么做呢?

答案

好吧,我希望我能以某种方式进入Message Driven Pojos生命周期来实现这一目标,但是通过其他关于异步代码的SO问题,我想出了一个基于CountDownLatch的解决方案

  1. 所有工作完成后,qazxsw poi注释方法应该在CountDownLatch上调用qazxsw poi: @JMSListener
  2. 在testMethod中 countDown()

此解决方案的缺点是您必须实际更改您的@JmsListener(destination = "dest", containerFactory = "cf") public void processMessage(TextMessage message) throws JMSException { //do the actual processing actualProcessing(message); //if there's countDownLatch call the countdown. if(countDownLatch != null) { countDownLatch.countDown(); } } 注释方法专门用于集成测试

另一答案

为了避免必须更改您的实际@JmsListener方法,您可以尝试在测试中使用AOP ...

首先创建一个像这样的方面类:

@Test
public void test() throws InterruptedException {
    //initialize the countDownLatch and set in on the processing class
    CountDownLatch countDownLatch = new CountDownLatch(1);
    messageProcessor.setCountDownLatch(countDownLatch);
    //sendthemessage
    sendSomeMessage();
    //wait for the processing method to call countdown()
    countDownLatch.await();
    verify();
}

然后将其添加到您用于测试的应用程序上下文配置中,如下所示:

@JMSListener

如果一切按计划进行,JmsListenerInterceptor将倒计时,您不必更改实际代码。

重要提示:我刚刚发现使用AOP和Mockito来验证@JmsListener中的某些方法是否被调用是一个糟糕的组合。原因似乎是CGLib类的额外包装导致调用错误/实际的目标实例而不是Mockito代理。

在我的测试中,我有一个@Autowired,@ InjectMocks Listener对象和一个@Mock Facade对象,我想验证它是否已经调用了某个方法。

使用AOP:

  • 测试线程: [JmsListenerTest] 2279812 - 类Listener $$ EnhancerBySpringCGLIB $$ 6587f46b(由Spring AOP包装) [JmsListenerTest] 30960534 - 类Facade $$ EnhancerByMockitoWithCGLIB $$ 69fe8952(由Mockito包装)
  • 监听线程: [Listener] 1151375 - 类Listener(AOP包装类的目标实例) [Listener] 4007155 - 类FacadeImpl(不是我们预期的实际实例)

没有AOP:

  • 测试线程: [JmsListenerTest] 10692528 - 类Listener(实际实例) [JmsListenerTest] 823767 - 类Facade $$ EnhancerByMockitoWithCGLIB $$ 773538e8(由Mockito包装)
  • 监听线程: [听众] 10692528 - 类Listener(仍为实际实例) [听众] 823767 - 类门面$$ EnhancerByMockitoWithCGLIB $$ 773538e8(仍为我们的模拟实例)

这表明你需要按照我尝试的方式注意使用AOP,因为你可能最终在两个线程中都有不同的实例......

另一答案

如果要将记录添加到@JmsListener带注释的方法,则可以在测试类中执行类似的操作

@Aspect
public static class JmsListenerInterceptor {
    @org.aspectj.lang.annotation.After("@annotation(org.springframework.jms.annotation.JmsListener)")
    public void afterOnMessage(JoinPoint jp) {
        // Do countdown latch stuff...
    }
}

以上是关于如何等待@JMSListener注释方法在JUnit中完成的主要内容,如果未能解决你的问题,请参考以下文章

如何访问@JmsListener使用的Spring Boot中的活动JMS连接/会话

Spring JMS:为@JmsListener注解的方法设置ErrorHandler

Spring 4.1 @JmsListener 配置

如何使用@JmsListener 暂停并开始使用消息

我怎样才能停止/启动/暂停@JmsListener(干净的方式)

从配置属性动态设置@JmsListener 目标