当前位置: 首页 > 知识库问答 >
问题:

SpringBoot应用程序中@RabbitListener方法测试

胡承载
2023-03-14
@Component
public class ServerThroughRabbitMQ implements ServerThroughAMQPBroker {
    private static final AtomicLong ID_COUNTER=new AtomicLong();
    private final long instanceId=ID_COUNTER.incrementAndGet();


    @Autowired
    public ServerThroughRabbitMQ( UserService userService,LoginService loginService....){
....
    }

    @Override
    @RabbitListener(queues = "#{registerQueue.name}")
    public String registerUserAndLogin(String json) {
       .....
    }
@Configuration
public class ServerConfig {
    @Value("${amqp.broker.exchange-name}")
    private String exchangeName;
    @Value("${amqp.broker.host}")
    private String ampqBrokerHost;
    @Value("${amqp.broker.quidco.queue.postfix}")
    private String quidcoQueuePostfix;
    @Value("${amqp.broker.quidco.queue.durability:true}")
    private boolean quidcoQueueDurability;
    @Value("${amqp.broker.quidco.queue.autodelete:false}")
    private boolean quidcoQueueAutodelete;

    private String registerAndLoginQuequName;


    @PostConstruct
    public void init() {
        registerAndLoginQuequName = REGISTER_AND_LOGIN_ROUTING_KEY + quidcoQueuePostfix;
    public String getRegisterAndLoginQueueName() {
        return registerAndLoginQuequName;
    }

    public String getLoginAndCheckBonusQueueName() {
        return loginAndCheckBonusQuequName;
    }



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

    @Bean
    public AmqpAdmin amqpAdmin() {
        return new RabbitAdmin(connectionFactory());
    }

    @Bean
    public TopicExchange topic() {
        return new TopicExchange(exchangeName);
    }

    @Bean(name = "registerQueue")
    public Queue registerQueue() {
        return new Queue(registerAndLoginQuequName, quidcoQueueDurability, false, quidcoQueueAutodelete);
    }


    @Bean
    public Binding bindingRegisterAndLogin() {
        return BindingBuilder.bind(registerQueue()).to(topic()).with(REGISTER_AND_LOGIN_ROUTING_KEY);
    }

   }
@EnableRabbit
@TestPropertySource("classpath:test.properties")
public class ServerThroughAMQPBrokerRabbitMQIntegrationTestConfig {
    private final ExecutorService=Executors.newCachedThreadPool();
    private LoginService loginServiceMock=mock(LoginService.class);
    private UserService userServiceMock =mock(UserService.class);

    @Bean
    public ExecutorService executor() {
        return executorService;
    }

    @Bean
    public LoginService getLoginServiceMock() {
        return loginServiceMock;
    }

    @Bean
    public UserService getUserService() {
        return userServiceMock;
    }

    @Bean
    @Autowired
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMaxConcurrentConsumers(5);
        return factory;
    }

    @Bean
    @Autowired
    public RabbitTemplate getRabbitTemplate(ConnectionFactory connectionFactory) {
        final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

    @Bean
    public ServerThroughRabbitMQ getServerThroughRabbitMQ() {
        return new ServerThroughRabbitMQ(userServiceMock, loginServiceMock,...);
    }

}

集成测试:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes ={ServerConfig.class,ServerThroughAMQPBrokerRabbitMQIntegrationTestConfig.class})
@Category({IntegrationTest.class})
@TestPropertySource("classpath:test.properties")
public class ServerThroughAMQPBrokerRabbitMQIntegrationTest {
    final private ObjectMapper jackson = new ObjectMapper();
    @Autowired
    private ExecutorService executor;

    @Autowired
    private ServerThroughRabbitMQ serverThroughRabbitMQ;

    @Autowired
    private RabbitTemplate template;

    @Autowired
    private TopicExchange exchange;

    @Autowired
    UserService userService;

    @Autowired
    LoginService loginService;

    @Autowired
    private AmqpAdmin amqpAdmin;

    @Autowired
    private ServerConfig serverConfig;

    final String username = "username";
    final String email = "email@email.com";
    final Integer tcVersion=1;
    final int quidcoUserId = 1;
    final String jwt = ProcessLauncherForJwtPhpBuilderUnitWithCxtTest.EXPECTED_JWT;


    @Before
    public void cleanAfterOthersForMyself() {
        cleanTestQueues();
    }

    @After
    public void cleanAfterMyselfForOthers() {
        cleanTestQueues();
    }

    private void cleanTestQueues() {
        amqpAdmin.purgeQueue(serverConfig.getRegisterAndLoginQueueName(), false);
    }

    @Test
    @Category({SlowTest.class,IntegrationTest.class})
    public void testRegistrationAndLogin() throws TimeoutException {
        final Waiter waiter = new Waiter();

        when(userService.register(anyString(), anyString(), anyString())).thenReturn(...);
        when(loginService....()).thenReturn(...);


        executor.submit(() -> {
            final RegistrationRequest request = new RegistrationRequest(username, email,tcVersion);
            final String response;
            try {
                //@todo: converter to convert RegistrationRequest inside next method to json
                response = (String) template.convertSendAndReceive(exchange.getName(), REGISTER_AND_LOGIN_ROUTING_KEY.toString(), jackson.writeValueAsString(request));
                waiter.assertThat(response, not(isEmptyString()));

                final RegistrationResponse registrationResponse = jackson.readValue(response, RegistrationResponse.class);
                waiter.assertThat(...);
                waiter.assertThat(...);

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            waiter.resume();
        });

        waiter.await(5, TimeUnit.SECONDS);
    }

}

当我偶尔运行这个测试时,一切都很好,但是当我和其他测试一起运行它时,没有使用模拟的ServerThroughRabbitMQ,所以一些spring缓存强制使用旧的rabbit侦听器。

我试图调试它,我可以看到,正确的bean被autowired到测试中,但由于某些原因旧监听器使用(旧bean字段instanceID=1新mocked bean instanceID=3),测试失败(不确定这是怎么可能的,所以如果存在旧bean,我假设得到autowire异常)。

我尝试使用@dirtiescontext BEFORE_CLASS,但遇到了一个问题(请参见此处)

共有1个答案

冀胤运
2023-03-14

RabbitMQ和集成测试可能很难,因为Rabbit MQ保持某种状态:-来自队列中先前测试的消息-来自先前测试的监听器仍在侦听队列

有几种方法

  • 在开始测试之前清除所有队列(这可能是您所说的cleanTestQueues())
  • 删除所有队列(或使用临时队列)并在每次测试前重新创建它们
  • 使用Rabbit Admin Rest API杀死以前测试的监听器或连接
  • 删除vhost并为每个测试重新创建基础架构(这是最残忍的方式)
 类似资料:
  • 使用spring-boot时,一切工作都很好。尽管如此,在spring-boot中已删除了注释和。我试图将代码重构为新版本,但我做不到。对于以下测试,我的应用程序在测试之前没有启动,http://localhost:8080返回404: 如何重构测试以使其在Spring-Boot1.5中工作?

  • 我的SpringBoot应用程序中有一个控制器: 我想在mocks的帮助下,将其与服务分开进行测试。如何实施?

  • 我有一个应用类 我有控制器课 并且,我想为Application test编写一个测试用例,以确保创建的实例类型为HelloController 但是,我在自动连接 hello控制器变量时遇到错误(找不到 hello 控制器类型的 bean)。根据我的理解,@SpringBootTest应该创建上下文并返回一个实例。我们不需要编写任何上下文 xml 或使用任何注释Config 类来获取实例。缺少了

  • 我试图在SpringMVC中运行SpringBoot应用程序,在SpringMVCPOM中添加SpringBoot应用程序依赖项,并扫描SpringBoot包,但我面临以下问题

  • 我正在使用一个spring启动应用程序,它运行我的src/main/resources/config/application。yml。 当我通过以下方式运行测试用例时: 测试代码仍在运行我的应用程序。要加载属性的yml文件。我想知道是否有可能再运行一个*。运行测试用例时的yml文件。

  • 我被要求在一个非常大的SpringBoot项目中为一个服务创建一个集成测试,该项目产生了几十个已实现的服务。当应用程序执行时,所有这些服务都被部署了——我希望避免部署与我正在为其创建测试的服务无关的所有服务。不幸的是,我(还)没有像我希望的那样有很多Spring启动测试的经验,因此我想知道解决这个问题的最佳方法是什么。 我曾考虑在测试类中使用注释对所有不相关的服务进行注释,并使用对所有相关服务进行