You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为返回Mono的Spring Webflux服务类编写组件测试

问题根因

你的submit方法存在核心的Reactor流操作逻辑错误:
调用bodyToMono(Void.class)得到的Mono<Void>是只会发射完成信号、不会发射任何数据元素的特殊Publisher。而map操作符仅会对上游发射的数据元素做转换,上游没有元素下发时map里的生成响应逻辑永远不会执行,最终返回的Mono直接完成,调用block()自然得到null。

修复业务代码

把map换成then操作符即可,then会等待上游Mono<Void>完成后,再切换到你指定的下游Publisher:

private Mono<SubmissionResponse> submit(Submission mySubmission)  {
  return webClient
        .post()
        .uri("/submit")
        .body(Mono.just(mySubmission), Submission.class)
        .retrieve()
        .onStatus(status -> status.equals(HttpStatus.NOT_FOUND), resp -> Mono.just(new SubmissionNotFoundException("No Submission found", HttpStatus.NOT_FOUND.name())))
        .bodyToMono(Void.class)
        // 替换map为then,等待上游完成后生成响应
        .then(Mono.fromSupplier(() -> myResponseGenerator.generateResponse(mySubmission)));
}

如果下游接口实际会返回响应体,也可以根据返回值类型调整bodyToMono的参数类型,不要用Void,这样map也能正常触发。

正确的组件测试编写

1. 配置正确的WireMock桩

要匹配WebClient的调用方法、路径、请求体,返回你预期的状态码:

// WireMock 桩配置示例
stubFor(post(urlEqualTo("/submit"))
        .withRequestBody(equalToJson(/* mySubmission序列化后的JSON串 */))
        .willReturn(aResponse()
                .withStatus(201)
        )
);

2. 推荐用StepVerifier做响应式测试

相比手动block,StepVerifier更符合响应式测试规范,能更方便的断言流的行为:

// 导入reactor.test.StepVerifier
StepVerifier.create(submissionService.submit(mySubmission))
        // 断言会发出一个非空响应元素
        .expectNextMatches(response -> {
            // 这里添加你对response字段的校验逻辑
            return response != null;
        })
        // 断言流正常完成
        .verifyComplete();

修复业务代码后,你原本用block的写法也能拿到非null的response对象。

额外注意点

  • 确保测试上下文里WebClient的baseUrl配置为WireMock的监听地址,端口不要填错
  • 如果有超时、重试逻辑,测试时可以适当调整超时时间避免流提前中断
  • 确保myResponseGenerator是被Spring正确注入的实例,避免生成响应时抛出空指针被流吞掉

内容的提问来源于stack exchange,提问作者Spartacus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 11:54:00