我有一个正在测试的 JMSInboundGateway,它监听 Apache Artemis 队列(竞争消费者)。我的测试向 Artemis 服务器发送消息并模拟目标服务。如果调用了模拟服务,那么我已验证 JmsInboundGateway 已正确设置。
流程如下所示:
测试发送者 -> Artemis 队列 -> JmsInboundGateway -> DirectChannel -> ServiceActivator -> Mock(目标服务)
如果它是 JUnit 测试套件中运行的唯一测试类,则测试运行得非常顺利;但是,如果套件中还有其他测试类,则测试失败。我已经追踪到,当测试失败时,Artemis 队列最多有三个消费者:我假设两个用于没有 Mocked 服务 bean 的 ApplicationContexts,另一个用于具有 mocked bean 的上下文。测试通过或失败取决于正确的上下文是否收到消息。
我尝试过的一件似乎有效的事情是在特定配置文件处于 Activity 状态时选择性地注册 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 { ... }
这对我来说也显得笨拙,但这是迄今为止我最好的解决方案。是否有任何我缺少的测试助手和/或模式可以帮助我解决这个问题?
非常感谢!
最佳答案
有了 @DirtiesContext
,你真的走对了路。
您在测试类中的应用程序上下文之间共享 JMS 资源的问题。这就是您真正与一个或另一个现有消费者发生冲突的方式,只是因为另一个类的整个应用程序上下文在执行期间被缓存,并且它可以访问 JMS 以及您的当前上下文。
这确实是我们几年前在 Spring Integration 中为我们的 JMS 和 JDBC 测试解决类似问题的方式。我们还要求 Spring Test Framework 开发人员将此作为默认功能来执行,但这听起来是一个重大的突破性变化,并且对于不共享资源的典型单元测试来说是不合理的。
从那以后,我们的方向是始终考虑我们的测试是否启动了一些后台线程或访问共享资源,例如嵌入式 MongoDB、Hazelcast 或文件系统上的某个目录。所以,在那些情况下,我们肯定会使用 @DirtiesContext
并且对通过的测试非常满意。
关于java - 监听竞争消费者队列的多个测试应用程序上下文导致间歇性测试失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51143627/