为何含expectAccessibleContext的Reactor测试代码执行失败?
错误核心原因
关于flatMap未执行的误解:你描述的"flatMap从未执行"大概率不准确——
Mono.just("Start")一定会发出元素,经过map转换为Optional.of("Start")后,defaultIfEmpty不会触发(因为上游有元素),所以flatMap必然会被执行。如果确实未执行,排查方向是map操作是否有未捕获的异常(但这里Optional.of("Start")不会抛异常)或OID的定义是否有误。上下文断言失败的真正原因:
第一个代码中,contextWrite被放在then()之后,而then()会忽略上游元素,仅返回一个Mono<Void>(仅发出onComplete信号)。虽然contextWrite修改了这个Mono<Void>的上下文,但map+defaultIfEmpty的链式调用会创建新的Mono实例,导致上下文传递链出现隐式隔离,StepVerifier无法捕获到onComplete信号携带的修改后上下文。
而第二个代码中,flatMap直接作用在原始Mono上,没有额外的map+defaultIfEmpty环节,onComplete信号的上下文能被StepVerifier正常捕获,因此断言成功。
修复方案
方案1:调整contextWrite的位置
将contextWrite移到then()之前,确保上下文修改作用在带有元素的Mono上,then()返回的完成信号会继承这个上下文:
@Test void name() { StepVerifier.create(Mono.just("Start") .map(val -> Optional.of(val)).defaultIfEmpty(Optional.empty()) .flatMap(val -> Mono.just(val).contextWrite(ctx -> ctx.put(OID, "Hey")).then())) .expectAccessibleContext() .contains(OID, "Hey") .then() .verifyComplete(); }
方案2:替换then()为直接返回完成信号
如果不需要处理上游元素,直接返回一个带上下文的空完成信号,避免then()的隐式上下文传递问题:
@Test void name() { StepVerifier.create(Mono.just("Start") .map(val -> Optional.of(val)).defaultIfEmpty(Optional.empty()) .flatMap(val -> Mono.fromRunnable(() -> {}).contextWrite(ctx -> ctx.put(OID, "Hey")))) .expectAccessibleContext() .contains(OID, "Hey") .then() .verifyComplete(); }
修复逻辑说明
两种方案都确保了contextWrite修改的上下文能被传递到最终的onComplete信号中,StepVerifier的expectAccessibleContext就能捕获到带有OID的上下文,断言通过。
内容的提问来源于stack exchange,提问作者So Hard

