如何用Awaitility验证事件未发生?现有实现报错求解
问题分析与解决方案
问题根源
你的代码逻辑存在两个核心问题:
- 条件判断写法冗余易混淆:通过
findFirst().orElse(null)再匹配nullValue的方式,本质是判断“无匹配记录”,但这种写法不如直接用noneMatch语义明确,也容易在Awaitility的条件校验中产生歧义。 - 对
during方法的理解偏差:during(Duration)的作用是验证条件在指定时长内持续成立,而非“等待一段时间后检查条件”。错误信息显示条件当前值符合预期(expected null but was null),但Awaitility未完成“条件持续满足15秒”的要求,因此抛出超时异常。
正确代码示例
根据你的需求(确保操作后数据库未出现特定新记录),分两种场景给出实现:
场景1:确保15秒内持续无目标记录(最长等待19秒完成校验)
如果需要验证操作完成后,接下来的15秒内始终不会出现目标记录,使用during配合noneMatch:
messages = new String[] {"message1", "message2"}; List<String> targetMessages = Arrays.asList(messages); await("wait for no target records to persist") .during(Duration.ofSeconds(15)) .atMost(Duration.ofSeconds(19)) .pollInterval(Duration.ofSeconds(1)) .until(() -> databaseService.getJournalRecords().stream() .noneMatch(record -> targetMessages.contains(record.getMessage())) );
- 逻辑说明:Awaitility会先等待条件变为真(无目标记录),然后开始计时15秒,确保这段时间内条件持续成立;如果中途条件失效(出现目标记录),会重新等待条件变为真并重新计时,最长等待19秒完成整个校验流程。
场景2:等待最多19秒,确认无目标记录
如果仅需确认操作完成后,经过足够长时间(19秒)仍无目标记录,无需持续校验,直接去掉during:
messages = new String[] {"message1", "message2"}; List<String> targetMessages = Arrays.asList(messages); await("wait for no target records") .atMost(Duration.ofSeconds(19)) .pollInterval(Duration.ofSeconds(1)) .until(() -> databaseService.getJournalRecords().stream() .noneMatch(record -> targetMessages.contains(record.getMessage())) );
- 逻辑说明:只要在19秒内条件变为真(无目标记录),就会立即通过;如果19秒后条件仍为假(存在目标记录),则抛出超时异常。
关键优化点
- 使用
noneMatch直接判断“无匹配记录”,语义清晰,避免findFirst().orElse()的冗余操作。 - 根据实际需求选择是否使用
during:需要持续校验用during,仅需最终状态校验则去掉。
内容的提问来源于stack exchange,提问作者Aleksey Bakharev
相关产品推荐
相关产品推荐

