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

Spring WebFlux单元测试如何提取WebClient发送的客户端请求体

解决方案

核心实现逻辑

ClientRequest本身提供writeTo方法可以将请求体序列化到数据缓冲区,我们可以通过这个方法提取完整请求体,完全适配你现有的测试方案,不需要额外引入依赖或全量Mock WebClient。

完整代码示例

首先定义用于存储捕获请求信息的实体类:

// 引入lombok.Data可省略Getter/Setter代码,没有lombok自行补全对应方法即可
@Data
public class CapturedRequest {
    private URI uri;
    private HttpHeaders headers;
    private String body;
}

修改你现有的@BeforeEach逻辑:

private CapturedRequest capturedRequest;
private ObjectMapper objectMapper = new ObjectMapper();

@BeforeEach
void preProgramWebClientBuilder() {
    capturedRequest = new CapturedRequest();
    DefaultDataBufferFactory bufferFactory = new DefaultDataBufferFactory();

    webClient = WebClient.builder()
        .baseUrl(TEST_REMOTE_BASE_URL)
        .exchangeFunction(clientRequest -> {
            // 先捕获基础请求信息
            capturedRequest.setUri(clientRequest.url());
            capturedRequest.setHeaders(clientRequest.headers());

            // 提取请求体逻辑
            DefaultDataBuffer buffer = bufferFactory.allocateBuffer();
            return clientRequest.writeTo(buffer, new ExchangeStrategies.DefaultExchangeStrategiesBuilder().build())
                .then(Mono.fromCallable(() -> {
                    // 将缓冲区内容转成字符串
                    byte[] bytes = new byte[buffer.readableByteCount()];
                    buffer.read(bytes);
                    DataBufferUtils.release(buffer); // 必须释放避免内存泄漏
                    capturedRequest.setBody(new String(bytes, StandardCharsets.UTF_8));
                    
                    // 返回模拟响应,避免业务逻辑因为无响应报错
                    return ClientResponse.create(HttpStatus.OK)
                        .header("Content-Type", "application/json")
                        .body("{}")
                        .build();
                }));
        }).build();

    when(webClientBuilder.baseUrl(anyString())).thenReturn(webClientBuilder);
    when(webClientBuilder.build()).thenReturn(webClient);
}

断言示例

测试方法中可以直接对捕获的请求信息做任意断言:

@Test
void testServiceRequestIsCorrect() {
    // 调用你的业务服务方法触发请求
    yourService.doBusiness().block();
    
    // 断言URI、请求头等基础信息
    assertEquals("/api/order", capturedRequest.getUri().getPath());
    assertEquals("Bearer test-token", capturedRequest.getHeaders().getFirst(HttpHeaders.AUTHORIZATION));
    
    // 直接断言请求体字符串
    assertEquals("expectedRequestBodyContent", capturedRequest.getBody());
    // 如果是JSON格式请求体,还可以转成对应DTO做字段级断言
    OrderRequestDto requestDto = objectMapper.readValue(capturedRequest.getBody(), OrderRequestDto.class);
    assertEquals(1001, requestDto.getOrderId());
    assertEquals("test_user", requestDto.getUserId());
}

注意事项

  • 如果请求体是表单格式,可以直接按字符串拆分解析,或者用Spring自带的表单解码器转换为键值对
  • 模拟返回的响应内容可以根据业务逻辑的要求自定义,避免服务层因为响应格式不符合预期中断测试

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 12:54:08