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

如何Mock WebClient的onStatus方法以覆盖测试代码分支?

如何Mock WebClient的onStatus()分支以覆盖4xx错误处理代码

要覆盖WebClient中onStatus()处理4xx错误的代码分支,你需要模拟一个4xx状态的响应,并确保onStatus()的谓词条件被触发,执行对应的错误逻辑。以下是具体的修改步骤和完整测试用例:

问题根源

你的原有测试用例模拟了正常成功的响应(Mono.just(...)),不会触发onStatus(HttpStatus::is4xxClientError, ...)的分支判断。需要构造一个4xx状态的响应场景,让该分支的代码被执行。

修改后的测试用例

@Test
void test4xxClientErrorHandling() throws URISyntaxException, InterruptedException, ExecutionException {
    // GIVEN
    DtoReq requestDTO = new DtoReq();
    String expectedErrorMessage = "4xx Client Error";

    // Mock WebClient的各阶段Spec
    WebClient.RequestBodyUriSpec requestBodyUriSpec = mock(WebClient.RequestBodyUriSpec.class);
    WebClient.RequestHeadersSpec<?> headerSpec = mock(WebClient.RequestHeadersSpec.class);
    WebClient.RequestBodySpec bodySpec = mock(WebClient.RequestBodySpec.class);
    WebClient.ResponseSpec responseSpec = mock(WebClient.ResponseSpec.class);

    // 构建WebClient调用链的Mock
    given(webClient.patch()).willReturn(requestBodyUriSpec);
    given(requestBodyUriSpec.uri(anyString())).willReturn(headerSpec);
    given(headerSpec.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)).willReturn(bodySpec);
    given(bodySpec.bodyValue(any(DtoReq.class))).willReturn(bodySpec);
    given(bodySpec.retrieve()).willReturn(responseSpec);

    // Mock onStatus方法:验证4xx谓词匹配,并触发错误处理逻辑
    given(responseSpec.onStatus(
            argMatches(predicate -> predicate.test(HttpStatus.BAD_REQUEST)),
            any(Function.class)
    )).willAnswer(invocation -> {
        // 获取传入的错误处理函数
        Function<ClientResponse, Mono<? extends Throwable>> errorHandler = invocation.getArgument(1);
        // 构造一个4xx状态的ClientResponse
        ClientResponse mockClientResponse = mock(ClientResponse.class);
        given(mockClientResponse.statusCode()).willReturn(HttpStatus.BAD_REQUEST);
        // 执行错误处理函数(覆盖onStatus内的代码分支)
        errorHandler.apply(mockClientResponse);
        return responseSpec;
    });

    // Mock bodyToMono返回4xx异常,触发整个错误链路
    given(responseSpec.bodyToMono(DVAUpdateStatusResponse.class)).willReturn(Mono.error(
            WebClientResponseException.create(400, "Bad Request", HttpHeaders.EMPTY, null, null, null)
    ));

    // WHEN & THEN
    // 验证最终抛出的异常(由onStatus+onErrorResume包装后的RuntimeException)
    RuntimeException thrown = assertThrows(RuntimeException.class, 
            () -> integrationService.toBeTested(requestDTO).get());
    assertTrue(thrown.getMessage().contains("error:"));
}

关键说明

  1. 模拟4xx响应状态:通过WebClientResponseException构造400错误的异常,让bodyToMono返回错误信号,触发onStatus的分支判断。
  2. 触发onStatus内的逻辑:在willAnswer中手动调用传入的错误处理函数,确保onStatus内的Mono.error(new RuntimeException(errorMessage))代码被执行,覆盖该分支。
  3. 链式调用保持:确保每个WebClient的Spec方法(如onStatus)都返回对应的Spec对象,维持调用链的完整性。
  4. 验证异常:通过assertThrows验证最终抛出的异常,确保错误链路执行正常。

额外优化建议

  • 如果需要验证日志输出(比如log.info("success", res)或错误日志),可以使用@MockBean注入Logger并验证调用。
  • 可以使用ArgumentMatchers的eq(HttpStatus::is4xxClientError)替代argMatches,但需要注意方法引用的匹配(部分Mockito版本可能需要调整)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:02:32