如何在模块/集成测试中禁用 Spring SQS 处理程序

Posted

技术标签:

【中文标题】如何在模块/集成测试中禁用 Spring SQS 处理程序【英文标题】:How to disable Spring SQS handler in module/integration test 【发布时间】:2017-10-17 20:32:05 【问题描述】:

我有一个 Spring Boot 应用程序,它只是通过具有 @SqsListener 注释方法的组件“MessageHandler”侦听 SQS 队列,并在消息到达时开始一些工作。

还有一个 boot-starter-web 依赖项,因为我们想在生产环境中通过 http 获取健康状态和指标。

现在我想编写一个模块测试,它已经有一个应用程序上下文和自动装配 bean。我还发现了如何禁用测试不需要的 Web 服务器:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = NONE)

但是,MessageHandler bean 也被实例化并尝试连接到 AWS,我想阻止这种情况。

一个可行的解决方案是在 src/test/java 中使用@Primary 注释进行测试实现,其handleMessage 方法没有@SqsListener 注释:

@Component
@Primary
public class TestMessageHandler implements MessageHandler 

    @Override
    public void handleMessage(final NewMessage newMessage) throws Exception 
        return null;
    

但是现在我还想测试(真正的)MessageHandler bean,这意味着,我希望 Spring 实例化它并自动装配它的依赖项,但我仍然不希望 @SqsListener 注释变为活动状态,所以我可以在我的测试中这样调用它:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = NONE)
public class IntegrationTest 

    @Autowired
    private RealMessageHandler messageHandler;


    @Test
    public void testHandleMessage() throws Exception 
        messageHandler.handleMessage(new NewMessage(...));
    

所以我需要关闭 spring-cloud-aws-starter 模块的魔法,该模块为 RealMessageHandler 中的 handleMessage 方法设置 SQS 侦听器。

知道我会怎么做吗?

【问题讨论】:

【参考方案1】:

我遇到了类似的问题,并通过模拟 SimpleMessageListenerContainer bean 解决了它。我计划为多个集成测试执行此操作,以便让这些测试更具可读性,我创建了一个 @TestConfiguration 类,然后将其导入到测试中。

这是我的配置类:


/**
 * Configuration class for integration test that do not need message listening capabilities.
 */
@TestConfiguration
public class MockMessageListenerConfiguration 

  @MockBean
  private SimpleMessageListenerContainer messageListenerContainer;



我是这样使用它的:

@SpringBootTest
@Import(MockMessageListenerConfiguration.class)
class BookingRepositoryIT ...

在此之后,与 AWS SQS 相关的连接拒绝警告消失了。

【讨论】:

【参考方案2】:

对于那些想要在不模拟实际队列发送/接收过程的情况下测试应用程序的人,您可以执行以下操作。

在测试中自动装配消息模板,然后像这样禁用侦听器:

@Autowired
private SimpleMessageListenerContainer simpleMessageListenerContainer;
@Autowired
private QueueMessagingTemplate queueMessagingTemplate;

@Test
public void test() 
String logicalQueueName = "my-queue";
simpleMessageListenerContainer.stop(logicalQueueName);
// code that will trigger message to be inserted into the queue

    Message<?> msg = ((QueueMessagingTemplate) queueMessagingTemplate)
        .receive(logicalQueueName);
// process msg

请记住,监听器不会在之后自动启动,因此您可以考虑在测试类中使用 DirtiesContext 注释。

【讨论】:

以上是关于如何在模块/集成测试中禁用 Spring SQS 处理程序的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 spring 集成来调整 sqs 队列的消耗

如何在 Spring Boot 2.2.0 的集成测试中禁用安全性?

无法使用测试容器的 localstack 模块连接到 Aws SQS

如何修改 Spring Cloud AWS 用来反序列化 SQS 消息的对象映射器?

如何将 API Gateway 与 SQS 集成

从 Spring-Boot 测试中排除 elasticsearchTemplate