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

Java 在竞争消费者队列上侦听的多个测试应用程序上下文会导致间歇性测试失败,java,spring-boot,spring-integration,integration-testing,spring-test,Java,Spring Boot,Spring Integration,Integration Testing,Spring Test,我正在测试一个JMSInboundGateway,它监听apacheartemis队列(竞争消费者)。我的测试向Artemis服务器发送一条消息,并模拟目标服务。如果调用了mock服务,那么我已经验证了JmsInboundGateway是否正确设置 流程如下所示: testsender->Artemis Queue->JmsInboundGateway->DirectChannel->ServiceActivator->Mock(目标服务) 如果它是JUnit测试套件中运行的唯一测试类,那么测试

我正在测试一个JMSInboundGateway,它监听apacheartemis队列(竞争消费者)。我的测试向Artemis服务器发送一条消息,并模拟目标服务。如果调用了mock服务,那么我已经验证了JmsInboundGateway是否正确设置

流程如下所示:
testsender->Artemis Queue->JmsInboundGateway->DirectChannel->ServiceActivator->Mock(目标服务)

如果它是JUnit测试套件中运行的唯一测试类,那么测试运行起来就像一个champ;但是,如果套件中有其他测试类,则测试失败。我发现,当测试失败时,Artemis队列最多有三个使用者:我假定两个用于没有模拟服务bean的ApplicationContexts,另一个用于有模拟bean的上下文。测试是否通过取决于正确的上下文是否接收到消息

我尝试过的一件似乎有效的事情是,当特定配置文件处于活动状态时,可以选择注册JMSINBundGateway,并且只在消息传递测试(当然还有live应用程序)上激活该配置文件

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

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

// The following appears to permit me to have multiple messaging enabled tests
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("messaging")
@DirtiesContext
public class MessagingTest { ... }
这对我来说似乎也很笨拙,但这是迄今为止我最好的解决方案。是否有任何我缺少的测试助手和/或模式可以帮助我解决这个问题


非常感谢

@DirtiesContext
你真的走对了路

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

这就是几年前我们在Spring集成中为JMS和JDBC测试解决类似问题的方法。我们还要求Spring测试框架开发人员将此作为默认功能,但这听起来是一个巨大的突破性变化,对于不共享资源的典型单元测试来说是不合理的


既然如此,我们就要始终思考我们的测试是否启动了一些后台线程或访问了共享资源,例如嵌入式MongoDB、Hazelcast或文件系统上的某个目录。因此,在这些情况下,我们肯定会使用
@DirtiesContext
,并且对通过的测试非常满意。

即使您为每个测试使用专用队列,在任何具有活动组件(并且不会在多个测试类中重用)的测试配置上使用
@DirtiesContext
仍然是有益的,为了避免这些后台上下文占用资源(内存/cpu)。我们在Spring集成中有数百个JMS测试,这大大减少了测试套件的运行时间。
// The following appears to permit me to have multiple messaging enabled tests
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("messaging")
@DirtiesContext
public class MessagingTest { ... }