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

码:

RabbitMQListener:

@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) { ..... } 

SERVERCONFIG:

 @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); } } 

TestConfig:

 @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缓存强制使用旧的兔子监听器。

我尝试调试它,我可以看到,正确的bean正在自动连接到测试,但由于某种原因,旧的侦听器正在使用(旧的bean字段instanceId = 1新的模拟bean instanceId = 3)并且测试失败(不确定它是怎么回事可能,所以如果在现有的旧bean的情况下我假设得到一个autowireexception)。

我试图使用@DirtiesContext BEFORE_CLASS,但遇到了一个问题(见这里 )

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

有几种方法:

  • 在开始测试之前清除所有队列(这可能是cleanTestQueues()意思)
  • 删除所有队列(或使用临时队列)并在每次测试之前重新创建它们
  • 使用Rabbit Admin Rest API杀死先前测试的侦听器或连接
  • 删除vhost并为每个测试重新创建infrasture(这是最残酷的方式)