繁体   English   中英

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

[英]@RabbitListener method testing in SpringBoot app

码:

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的情况下我假设得到一个autowire异常)。

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

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

有几种方法:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM