如何用Mockito验证WebClient中Lambda表达式传入的请求头参数?
问题:如何用Mockito验证Spring WebClient添加的请求头?
我正在创建Spring WebClient,并为其构建器添加自定义请求头,代码如下:
@Component public class ApiClient { private final WebClient client; public Mono<Optional<String>> getApiInfo(final String header) { return client .get() .uri(URI) .headers(requestHeaders -> { requestHeaders.add("Header_name", "Header_Value"); if (StringUtils.isNotBlank(header)) { requestHeaders.add("Second_header", header); } }) .retrieve() // 后续处理逻辑省略 .bodyToMono(new ParameterizedTypeReference<Optional<String>>() {}); } }
我已Mock了所有构建步骤,但无法对headers()方法执行verify()操作,请问仅使用Mockito如何验证请求头已成功添加?
解决方法
WebClient的headers()方法接收的是Consumer<HttpHeaders>类型的参数(也就是你传入的lambda表达式),Mockito无法直接验证lambda内部的执行逻辑,因此需要通过捕获这个Consumer并手动执行的方式来验证请求头是否正确添加,具体步骤如下:
- Mock WebClient链式调用的所有中间对象:包括
RequestHeadersUriSpec、RequestHeadersSpec、ResponseSpec等,确保链式调用能正常走到headers()方法。 - 用ArgumentCaptor捕获传入headers()的Consumer:通过捕获这个Consumer,我们可以拿到你编写的请求头设置逻辑。
- 执行捕获到的Consumer并验证HttpHeaders:创建真实的
HttpHeaders实例,调用捕获到的Consumer,然后检查headers中的键值对是否符合预期。
测试代码示例
@ExtendWith(MockitoExtension.class) class ApiClientTest { @Mock private WebClient webClient; @Mock private WebClient.RequestHeadersUriSpec<?> requestHeadersUriSpec; @Mock private WebClient.RequestHeadersSpec<?> requestHeadersSpec; @Mock private WebClient.ResponseSpec responseSpec; @InjectMocks private ApiClient apiClient; // 验证正常传入header的场景 @Test void getApiInfo_withValidHeader_shouldAddBothHeaders() { // 模拟WebClient链式调用流程 when(webClient.get()).thenReturn(requestHeadersUriSpec); when(requestHeadersUriSpec.uri(any(URI.class))).thenReturn(requestHeadersSpec); // 捕获headers()方法的Consumer参数 ArgumentCaptor<Consumer<HttpHeaders>> headersCaptor = ArgumentCaptor.forClass(Consumer.class); when(requestHeadersSpec.headers(headersCaptor.capture())).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); // 模拟响应结果,适配业务方法的返回类型 when(responseSpec.bodyToMono(any(ParameterizedTypeReference.class))) .thenReturn(Mono.just(Optional.of("sample-response"))); // 调用目标方法 String testHeaderValue = "test-second-header"; apiClient.getApiInfo(testHeaderValue).block(); // 执行捕获到的Consumer,填充HttpHeaders HttpHeaders actualHeaders = new HttpHeaders(); headersCaptor.getValue().accept(actualHeaders); // 验证请求头 assertEquals("Header_Value", actualHeaders.getFirst("Header_name")); assertEquals(testHeaderValue, actualHeaders.getFirst("Second_header")); } // 验证header为空的场景 @Test void getApiInfo_withBlankHeader_shouldOnlyAddDefaultHeader() { // 重复链式调用模拟(可抽取为公共方法) when(webClient.get()).thenReturn(requestHeadersUriSpec); when(requestHeadersUriSpec.uri(any(URI.class))).thenReturn(requestHeadersSpec); ArgumentCaptor<Consumer<HttpHeaders>> headersCaptor = ArgumentCaptor.forClass(Consumer.class); when(requestHeadersSpec.headers(headersCaptor.capture())).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); when(responseSpec.bodyToMono(any(ParameterizedTypeReference.class))) .thenReturn(Mono.just(Optional.empty())); // 传入空header apiClient.getApiInfo("").block(); // 执行Consumer并验证 HttpHeaders actualHeaders = new HttpHeaders(); headersCaptor.getValue().accept(actualHeaders); assertEquals("Header_Value", actualHeaders.getFirst("Header_name")); assertNull(actualHeaders.getFirst("Second_header")); } }
关键说明
- 核心思路是捕获Consumer并触发执行,因为lambda是延迟执行的,只有当WebClient真正发送请求时才会执行,但测试中我们Mock了所有调用,所以需要手动触发这个逻辑来验证请求头。
- 要覆盖不同的分支场景(比如header为空/非空),分别编写测试用例确保所有逻辑都被验证到。
内容的提问来源于stack exchange,提问作者Milton Ortegon
相关产品推荐
相关产品推荐

