如何在 Spring Boot 测试中模拟 spring amqp/rabbit

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38746522/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 01:08:52  来源:igfitidea点击:

how to mock spring amqp/rabbit in spring boot test

springspring-testspring-amqpspring-rabbitspring-rabbitmq

提问by domi

How to mock spring rabbitmq/amqp so it will not fail during a Spring Boot Test while trying to auto create exchanges/queues?

如何模拟 spring rabbitmq/amqp 使其在 Spring Boot 测试期间不会在尝试自动创建交换/队列时失败?

Given I have a simple RabbitListenerthat will cause the queue and exchange to be auto created like this:

鉴于我有一个简单的方法RabbitListener,它将导致队列和交换被自动创建,如下所示:

@Component
@RabbitListener(bindings = {
        @QueueBinding(
                value = @Queue(value = "myqueue", autoDelete = "true"), 
                exchange = @Exchange(value = "myexchange", autoDelete = "true", type = "direct"), 
                key = "mykey")}
)
@RabbitListenerCondition
public class EventHandler {
    @RabbitHandler
    public void onEvent(Event event) {
      ...
    }   
}

During a simple Spring Boot Test, like this:

在一个简单的 Spring Boot 测试中,像这样:

@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = { Application.class })

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void test() {
        assertNotNull(applicationContext);
    }

}

it will fail with:

它会失败:

16:22:16.527 [SimpleAsyncTaskExecutor-1] ERROR o.s.a.r.l.SimpleMessageListenerContainer - Failed to check/redeclare auto-delete queue(s).
org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused
    at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:62)
    at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:309)

In in this test I don't care about Rabbit/AMQP, so how can I mock the whole Rabbit/AMQP away?

在这个测试中,我不关心 Rabbit/AMQP,那么我如何模拟整个 Rabbit/AMQP 呢?

采纳答案by Gary Russell

It's not particularly easy, we generally use a JUnit @Ruleto skip the test if the broker's not available.

这不是特别容易,@Rule如果代理不可用,我们通常使用 JUnit跳过测试。

However, we do have a lot of tests that use mocks, but you really have to understand a lot of the Spring AMQP internals to use them. You can explore the test cases in the project itself.

但是,我们确实有很多使用模拟的测试,但是您确实必须了解很多 Spring AMQP 内部结构才能使用它们。您可以探索项目本身中的测试用例。

At one point I did attempt writing a mock broker but it ended up being too much work.

有一次我确实尝试编写一个模拟经纪人,但最终工作量太大。

回答by Lo?c Le Doyen

I know this is an old topic, but I'd like to introduce a mocking library I'm developping : rabbitmq-mock.

我知道这是一个老话题,但我想介绍一个我正在开发的模拟库:rabbitmq-mock

The purpose of this mock is to mimic RabbitMQ behavior without IO (without starting a server, listening to some port, etc.) and with minor (~ none) startup time.

这个模拟的目的是在没有 IO(没有启动服务器、监听某个端口等)和有少量(~无)启动时间的情况下模拟 RabbitMQ 行为。

It is available in Maven Central:

它在 Maven 中心可用:

<dependency>
    <groupId>com.github.fridujo</groupId>
    <artifactId>rabbitmq-mock</artifactId>
    <version>1.0.14</version>
    <scope>test</scope>
</dependency>

Basic use will be to override Spring configuration with a test one :

基本用途是使用测试覆盖 Spring 配置:

@Configuration
@Import(AmqpApplication.class)
class AmqpApplicationTestConfiguration {

    @Bean
    public ConnectionFactory connectionFactory() {
        return new CachingConnectionFactory(MockConnectionFactoryFactory.build());
    }
}

For automatic mocking of Spring beans for tests, give a look at another project I'm working on: spring-automocker

要自动模拟 Spring bean 进行测试,请查看我正在从事的另一个项目:spring-automocker

Hope this can help !

希望这可以帮助!

回答by Rajkishan Swami

Not sure if this is helpful but, i was having the same problem. So, i just used @MockBeanon RabbitAdminwith a different profile, and did not get the same connection issues. Tests Passed.

不确定这是否有帮助,但是我遇到了同样的问题。所以,我只是用@MockBeanRabbitAdmin了不同的配置文件,并没有得到相同的连接问题。测试通过。

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@RunWith(SpringRunner.class)
@ActiveProfiles("my-test")
public class ServiceTests {

@Autowired
private DummyService unitUnderTest;

@MockBean
private RabbitAdmin rabbitAdmin;

// lots of tests which do not need Spring to Create a RabbitAdmin Bean
}

回答by joy

In our project, we initialize a RabbitMQinstance using a dockercontainer locally. To run an integration test, we do spin up a RabbitMQinstance at the beginning of the test case and shut it down during clean-up.

在我们的项目中,我们在本地RabbitMQ使用docker容器初始化一个实例。为了运行集成测试,我们RabbitMQ在测试用例开始时启动一个实例并在清理期间关闭它。

We're using TestContainers to do just that. Please see https://www.testcontainers.org/usage/dockerfile.htmland/or https://www.testcontainers.org/usage/docker_compose.html.

我们正在使用 TestContainers 来做到这一点。请参阅https://www.testcontainers.org/usage/dockerfile.html和/或https://www.testcontainers.org/usage/docker_compose.html

回答by Michail Michailidis

Somewhat similar to Rajkishan's answerthat didn't work for me:

有点类似于Rajkishan 的答案,但对我不起作用:

This is what worked for me instead:

这对我有用:

@SpringBootApplication
public class MyTestsApp {
    @Bean
    @Primary
    public CachingConnectionFactory rabbitAdmin() {
        return Mockito.mock(CachingConnectionFactory.class);
    }
}

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MyTestsApp.class})
@ActiveProfiles(profiles = "test")
public class MyTests {

}

回答by Vincent F

I was having a similar requirement at some point, and looked into QPid, which provides an in memory AMQP broker. It's forcing you to stay at the AMQP level, and use as little rabbitMq specific code as possible.

我在某个时候有类似的需求,并查看了 QPid,它提供了一个内存中的 AMQP 代理。它迫使您停留在 AMQP 级别,并尽可能少地使用 rabbitMq 特定代码。

But I actually found another way : by tweaking the names of queues and exchanges when running tests + the auto-delete value, we're not having the issue anymore. All queue/exchange names in tests are suffixed with the user name (of the account running the tests), meaning that everyone can run the tests on their machine without impacting others.

但我实际上找到了另一种方法:通过在运行测试时调整队列和交换的名称+自动删除值,我们不再有问题了。测试中的所有队列/交换名称都以用户名(运行测试的帐户的)为后缀,这意味着每个人都可以在自己的机器上运行测试而不会影响其他人。

Even in our CI pipeline, several projects may use the same exchanges/queues : we configure the values in tests to be project specific, so that even if 2 projects run their tests at the same time on the same machine with the same user, messages will not "leak" outside of current test.

即使在我们的 CI 管道中,几个项目也可能使用相同的交换/队列:我们将测试中的值配置为特定于项目,这样即使两个项目在同一台机器上以相同的用户同时运行它们的测试,消息不会在当前测试之外“泄漏”。

This ends up being much simpler to manage than mocking or spawning an in memory broker.

这最终比模拟或生成内存代理更容易管理。

回答by Dherik

First, create a @Configurationwith ConnectionFactoryin your test package:

首先,在您的测试包中创建一个@Configurationwith ConnectionFactory

@Configuration
public class RabbitMqConfiguration {

    @Bean
    ConnectionFactory connectionFactory() {
        return new CachingConnectionFactory();
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
       return new RabbitTemplate(connectionFactory);
    }

}

After that, set this property in your application.yml from test package:

之后,在测试包中的 application.yml 中设置此属性:

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration

This should work for Spring Boot 2.2.x.

这应该适用于 Spring Boot 2.2.x。

For Spring Boot 1.5.x I also needed to add one more dependency:

对于 Spring Boot 1.5.x,我还需要再添加一个依赖项:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-test-support</artifactId>
    <scope>test</scope>
</dependency>

I don't know why, but without the spring-cloud-stream-test-supportdependency my Integration Test try to connect on RabbitMQ broker. Even not affecting the result of the test itself, this stole a lot of seconds in each test. I already see this strange behavior in another post.

我不知道为什么,但没有spring-cloud-stream-test-support依赖我的集成测试尝试连接到 RabbitMQ 代理。即使不影响测试本身的结果,这在每次测试中也偷走了很多秒。我已经在另一篇文章中看到了这种奇怪的行为。