如何在集成测试中等待某些操作
Posted
技术标签:
【中文标题】如何在集成测试中等待某些操作【英文标题】: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 以防您将消息作为容器设置的一部分发送
【参考方案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 RetryTemplate 或Failsafe 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;
【讨论】:
你实际测试的是什么条件?以上是关于如何在集成测试中等待某些操作的主要内容,如果未能解决你的问题,请参考以下文章
在java Spring Boot中,如何在集成测试中将内存中的LDAPConnection对象传递给ldapService?
如何在 Maven 3 中运行嵌入式 Tomcat 9 以进行集成测试?