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
相关产品推荐
相关产品推荐

