6

我有一个 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 侦听器。

任何线索我会怎么做?

4

2 回答 2

6

我有一个类似的问题并通过模拟 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 相关的连接拒绝警告消失了。

于 2019-09-19T11:20:55.957 回答
0

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

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

@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在测试类中使用注释。

于 2020-05-08T15:35:17.170 回答