【问题标题】:How to wait in integration test for some operations如何在集成测试中等待某些操作
【发布时间】:2021-07-05 02:01:31
【问题描述】:

您好,我使用测试容器与 docker 进行了集成测试。在容器上我运行 jms。在测试中,我将消息放入队列。

如何在测试中等待以使其填充到 jms 上?

在本地机器上它可以工作,但在 jenkins 上它失败了,所以我必须添加

    Thread.sleep(3000);

但这很讨厌。 org.awaitility 似乎错过了用法:

await().atMost(2, TimeUnit.SECONDS).until(() -> return true));

我只需要暂停一下以使 jms 传播(放入 jms 队列)并等待侦听器采取行动,即将消息放入数据库。 然后我必须调用 get rest 端点来查看它是否有效。

使用主题会更容易,因为我会在主题上创建测试监听器。 但它是队列,可以有监听器来获取消息。

提前感谢您的任何建议

【问题讨论】:

  • 不知道你为什么叫 sleep nasty,这是一种解决方法,但它确实有效......有没有办法检查 jms 队列是否在你的 await().asMost() 调用中包含一条消息?跨度>
  • 使用sleep() 并不理想,因为它脆弱且效率低下。它很脆弱,因为如果机器速度更慢,那么睡眠时间仍然不够。这是低效的,因为如果机器加速,它将无缘无故地休眠。这真的可以加起来很多测试。
  • 您是使用 Testcontainers 容器定义还是在代码中填充消息? Testcontainers 提供了几种等待策略:testcontainers.org/features/startup_and_waits 以防您将消息作为容器设置的一部分发送

标签: docker jms integration-testing testcontainers jms-queue


【解决方案1】:

org.awaitility 与JMS QueueBrowser 一起使用,例如:

@Test
public void myTest() throws Exception {
   ...
   await().atMost(2, TimeUnit.SECONDS).until(() -> return queueIsEmpty(queueName)));
   ...
}

private boolean queueIsEmpty(String queueName) {
   ConnectionFactory cf = new MyBrokersConnectionFactory();
   Connection connection = cf.createConnection();
   Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
   QueueBrowser browser = session.createBrowser(session.createQueue(queueName));
   Enumeration enumeration = senderBrowser.getEnumeration();
   while (enumeration.hasMoreElements()) {
      return false;
   }
   return true;
}

QueueBrowser只读的,因此不会有实际消耗消息的危险。

另一个可能的选择是创建一个具有事务会话的消费者,然后尝试接收消息。如果你确实收到了一条消息,你可以回滚事务并关闭消费者。

【讨论】:

  • QueueBrowser 不是您可以依赖的东西。 Docs 表示
【解决方案2】:

使用重试(例如Spring RetryTemplateFailsafe Retry Policy)来缩短集成测试执行时间:

  • 重试 SQL 查询,直到出现记录
  • 重试 REST 端点,直到成功

这里是一个等待DB记录的例子;根据您的需要调整政策:

RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setBackOffPolicy(new FixedBackOffPolicy());
retryTemplate.setRetryPolicy(new SimpleRetryPolicy(
         10, Collections.singletonMap(AssertionError.class, true)));
retryTemplate.execute(retryContext -> {
    List<MyRecord> records = jdbcTemplate.query("select ...");
    Assert.assertEquals(1, records.size());
    return null;
});

【讨论】:

    【解决方案3】:

    我的解决方案是使用org.awaitility lib 并将断言替换为返回语句:

            await().atMost(30, TimeUnit.SECONDS).until(
                () -> {
                    //
                    // assertTrue(condition);
                    return condition == true;
                }
    

    【讨论】:

    • 你实际测试的是什么条件?
    猜你喜欢
    • 2019-12-09
    • 2012-02-25
    • 2021-10-03
    • 2020-01-17
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    相关资源
    最近更新 更多