如何使用StepVerifier稳定测试Redis infinite stream监听方法
问题根因
测试不稳定的核心原因是StreamReceiver的订阅是异步IO操作:调用streamFromLatest方法触发订阅后,StreamReceiver需要和Redis完成网络交互、注册监听、定位到latest偏移量,整个过程需要几十到几百毫秒不等。
原测试代码中StepVerifier的.then()回调会在订阅触发后立即执行,此时大概率还没完成Redis侧的订阅注册,写入的消息会被StreamOffset.latest策略跳过(只会消费订阅完成之后新增的消息)。Maven运行时测试执行速度更快,订阅未完成就发消息的概率为100%,因此必败;Eclipse运行时偶尔初始化速度够快,所以会偶发成功。
解决方案
完全可以通过调整StepVerifier逻辑实现稳定测试,不需要修改业务代码,推荐两种可行方案:
方案1:增加初始化等待(适配90%以上场景)
在发送消息前增加固定时长的等待,给StreamReceiver留够初始化时间,修改后的测试代码如下:
@Autowired private ClassUnderTest template; // 优先用原生ReactiveStringRedisTemplate,避免SpyBean代理增加延迟 @Autowired private ReactiveStringRedisTemplate reactiveStringRedisTemplate; @Test void streamFromLatest() { final ConfigurationRedis configRedis = ...; StepVerifier.create(template.streamFromLatest(streamKey)) .expectNextCount(0) // 等待500ms确保订阅初始化完成,可根据CI环境性能调整时长 .thenAwait(Duration.ofMillis(500)) .then(() -> reactiveStringRedisTemplate .opsForStream() .add(StreamRecords.objectBacked(configRedis).withStreamKey(streamKey)) .block()) .expectNext(configRedis) .thenCancel() .verify(Duration.ofSeconds(20)); }
方案2:重试发送消息(适配性能波动大的CI环境)
如果CI环境性能波动大,固定等待仍偶发失败,可以采用重试发送逻辑,确保订阅完成后消息能被接收到:
@Test void streamFromLatest() { final ConfigurationRedis configRedis = ...; StepVerifier.create(template.streamFromLatest(streamKey)) .expectNextCount(0) .then(() -> // 最多重试3次发送,每次间隔300ms Mono.defer(() -> reactiveStringRedisTemplate .opsForStream() .add(StreamRecords.objectBacked(configRedis).withStreamKey(streamKey)) ) .retryBackoff(3, Duration.ofMillis(300)) .block() ) .expectNextMatches(configRedis::equals) .thenCancel() .verify(Duration.ofSeconds(20)); }
额外优化建议
- 给Redis Testcontainers增加健康检测,确保Redis服务完全启动后再执行测试,避免网络波动影响
- 如果业务允许,可以给StreamReceiver增加订阅完成的回调钩子,测试时监听该钩子再触发消息发送,可完全消除无效等待时间
内容的提问来源于stack exchange,提问作者Joao Moreira
相关产品推荐
相关产品推荐

