在竞争的客户队列上侦听的多个测试应用程序上下文会导致间歇性测试失败

时间:2018-07-02 20:55:52

标签: java spring-boot spring-integration integration-testing spring-test

我有一个正在测试的JMSInboundGateway,它侦听Apache Artemis队列(竞争使用者)。我的测试将消息发送到Artemis服务器,并模拟目标服务。如果调用了模拟服务,那么我已经验证了JmsInboundGateway的设置正确。

流程如下所示: Test Sender -> Artemis Queue -> JmsInboundGateway -> DirectChannel -> ServiceActivator -> Mock(Destination Service)

如果测试是JUnit测试套件中唯一运行的测试类,则它会像冠军一样运行;但是,如果套件中还有其他测试类,则测试将失败。我已经跟踪到,当测试失败时,Artemis队列最多有三个使用方:我假设两个用于不具有Mocked服务bean的ApplicationContext,另一个用于具有模拟bean的上下文。测试是通过还是失败取决于正确的上下文是否接收到消息。

我尝试过的似乎起作用的一件事是,当特定配置文件处于活动状态时,有选择地注册JmsInboundGateway,并且仅在消息传递测试(当然还有实时应用程序)上激活该配置文件。

// Declaring my inbound gateways with the profile requirement
@Profile("messaging")
@Bean
public JmsInboundGateway jmsInboundGateway(ConnectionFactory connFactory) { ... }

// Running my tests with
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("messaging")
public class MessagingTest { ... }

这将导致消息窃取上下文永远不会侦听队列中的消息,并允许适当的上下文成为独占侦听器。这并不是一个特别令人满意的解决方案,因为我可能有多个测试类需要“消息传递”配置文件,并且我已验证它们可以互相踩脚。

如果我将@DirtiesContext批注添加到每个标有@ActiveProfiles(“ messaging”)的测试中,那么当存在多个消息传递测试时,这确实可以解决问题。我在测试套件执行期间仅观察到Artemis队列中的一个使用者,并且我可以启用多个测试类并启用消息传递。

// The following appears to permit me to have multiple messaging enabled tests
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("messaging")
@DirtiesContext
public class MessagingTest { ... }

在我看来这也很笨拙,但这是迄今为止我最好的解决方案。是否有我缺少的测试帮助程序和/或模式可以帮助我解决此问题?

非常感谢!

1 个答案:

答案 0 :(得分:3)

有了@DirtiesContext,您真的走对了。

在测试类的应用程序上下文之间共享JMS资源的问题。这就是您真正与一个或另一个现有使用者发生冲突的方式,只是因为在执行期间缓存了另一个类的整个应用程序上下文,并且它可以访问JMS以及您的当前上下文。

这确实是几年前我们在Spring Integration中解决JMS和JDBC测试中类似问题的方法。我们还要求Spring Test Framework开发人员将其作为默认功能来执行,但这听起来是一个重大突破,对于不共享资源的典型单元测试来说,这是不合理的。

自此以来,我们一直在指导我们始终思考测试是否启动了某些后台线程或是否可以访问共享资源,例如嵌入式MongoDB,Hazelcast或文件系统上的某个目录。因此,在那种情况下,我们肯定会使用@DirtiesContext,并且对通过的测试感到非常满意。