WebFlux+Spock测试中StepVerifier未触发Service方法执行问题
问题根源与解决办法
核心问题有两个:Reactor流是惰性执行的,且你在Spock测试里的断言顺序搞反了
为啥原测试跑失败?
- Reactor的数据流只有在被订阅之后才会真正执行,
StepVerifier.create()只是创建了验证器,还没触发流运行。 - 你现在的写法是先调用
result.verifyComplete()触发流执行,等流跑完了,才去注册Spock的Mock断言1 * service.test(_) >> true——这时候调用记录已经生成了,断言才刚加上,当然会提示方法从未被执行。
为啥加block()就能过?
block()是同步阻塞方法,会主动触发流执行,在控制器返回Mono.empty()之前,service.test()已经被调用过了,之后再执行Mock断言,自然能抓到调用记录。但这种写法在生产环境绝对不能用,会阻塞线程,完全违背WebFlux异步非阻塞的设计初衷。
正确的测试写法
把Spock的Mock断言放到流触发执行之前,也就是在verifyComplete()调用前注册好断言,保证流运行时断言已经生效。
调整后的测试代码:
def "Should test abc"() { setup: def testDto = new TestDto(11L, true) // 先注册Mock调用断言 1 * service.test(_) >> true when: def result = StepVerifier.create(controller.test(Flux.just(testDto))) then: result.verifyComplete() }
或者也可以把断言放到when块里,只要保证在verifyComplete()之前:
def "Should test abc"() { setup: def testDto = new TestDto(11L, true) when: // 先注册断言 1 * service.test(_) >> true def result = StepVerifier.create(controller.test(Flux.just(testDto))) // 触发流执行 result.verifyComplete() then: noExceptionThrown() }
为啥thenAwait没用?
你之前加的thenAwait只是让验证器等待,但核心问题是断言注册晚了,流已经跑完了才加断言,等再久也抓不到调用记录。只有让Mock断言在流启动前就位,才能正确捕获方法调用。
额外说明
生产环境代码是没问题的,因为Spring WebFlux处理请求时会自动订阅返回的Mono/Flux,触发流执行,所以实际运行一切正常。问题完全出在测试的断言顺序和Reactor的惰性执行特性不匹配上。
内容的提问来源于stack exchange,提问作者Bolek Lolek
相关产品推荐
相关产品推荐

