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

SpringBoot Mock WebClient时header返回空致空指针异常

解决WebClient Mock时的空指针异常

我们创建了SpringBoot应用,使用WebClient同步调用外部API,采用JUnit 5编写测试用例并通过Mockito Mock WebClient,但运行测试时出现如下空指针异常:

java.lang.NullPointerException: Cannot invoke "org.springframework.web.reactive.function.client.WebClient$RequestHeadersSpec.retrieve()" 
because the return value of "org.springframework.web.reactive.function.client.WebClient$RequestHeadersSpec.header(String, String[])" is null

测试用例代码

@SpringBootTest
@ActiveProfiles("test")
public class StrategyTest {
    @Mock
    private WebClient.RequestHeadersUriSpec<?> requestHeadersUriMock;
    @Mock
    private WebClient.RequestHeadersSpec<?> requestHeadersMock;
    @Mock
    private WebClient.ResponseSpec responseMock;
    @MockBean
    @Qualifier("kwebclient")
    private WebClient kwebclient;
    @MockBean
    private AuthTokenManager authTokenManager;
    @MockBean
    private TokenRefreshScheduler tokenRefreshScheduler;


    @Test
    void testOptimise1() {
        when(authTokenManager.getAuthToken()).thenReturn(authTokenResponse);
        prepareWebClientMock();
        CReady cReady = setTestCReady();
        Strategy.invokeGetScItem(LocationAPIUrl, lin, kwebclient, authTokenManager,
                tokenRefreshScheduler);
        assertNotNull(cReady);

    }

    private void prepareWebClientMock() {
        doReturn(requestHeadersUriMock).when(kongWebclient).get();
        lenient().when(requestHeadersUriMock.uri(Mockito.any(Function.class))).thenReturn(requestHeadersMock);

        doReturn(requestHeadersMock).when(requestHeadersMock).accept(notNull());
        doReturn(requestHeadersMock).when(requestHeadersMock).header(notNull(), 
         notNull());
        doReturn(responseMock).when(requestHeadersMock).retrieve();
        doReturn(Mono.just(APIResponseJsonString)).when(responseMock).toEntity(String.class);
    }
}

业务代码中API调用逻辑

Mono<ResponseEntity<String>> monoresponse = kWebclient.get()
        .uri(uriBuilder -> uriBuilder.path(finalurl).build())
        .header("Authorization", "Bearer " + authTokenManager.getAuthToken().getAccessToken()).retrieve()
        .toEntity(String.class);

response = monoresponse.block();

WebClient创建代码

@Bean
@Qualifier("kWebclient")
public WebClient createWebClient() throws Exception {
    return buildSslEnabledWebClient();
}

private WebClient buildSslEnabledWebClient() throws Exception {
    final KeyStore trustStore = createKeyStore(trustStorePath, 
     kConfigVault.getKTrustStorePassword());

    try {
        final TrustManagerFactory trustManager = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManager.init(trustStore);

        final SslContext sslContext = SslContextBuilder.forClient().trustManager(trustManager).build();

        final HttpClient httpClient = HttpClient.create().secure(ssl -> {
            ssl.sslContext(sslContext);
        });
        final int size = 16 * 1024 * 1024;
        final ExchangeStrategies strategies = ExchangeStrategies.builder()
                .codecs(codecs -> codecs.defaultCodecs().maxInMemorySize(size)).build();

        return WebClient.builder().exchangeStrategies(strategies)
                .clientConnector(new ReactorClientHttpConnector(httpClient)).build();

    } catch (NoSuchAlgorithmException | KeyStoreException | SSLException e) {
        log.error("Could not initialize Webclient with the trustore data", e);
        throw e;
    }
}

问题原因与修复方案

问题出在两个地方:

  1. 方法重载匹配错误:业务代码调用的是header(String, String)(单个字符串参数的重载),但测试中mock的header(notNull(), notNull())匹配的是header(String, String[])(数组参数的重载),导致实际调用时没有匹配到mock逻辑,返回null,触发空指针。
  2. 变量名笔误:测试中when(kongWebclient).get()里的kongWebclient是笔误,应该是kwebclient,否则get()方法的mock不会生效。

修正后的prepareWebClientMock方法

private void prepareWebClientMock() {
    // 修正变量名笔误
    doReturn(requestHeadersUriMock).when(kwebclient).get();
    lenient().when(requestHeadersUriMock.uri(Mockito.any(Function.class))).thenReturn(requestHeadersMock);

    doReturn(requestHeadersMock).when(requestHeadersMock).accept(notNull());
    // 匹配单个字符串参数的header重载
    doReturn(requestHeadersMock).when(requestHeadersMock).header(notNull(), anyString());
    doReturn(responseMock).when(requestHeadersMock).retrieve();
    doReturn(Mono.just(APIResponseJsonString)).when(responseMock).toEntity(String.class);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 05:42:32