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

Junit测试ExchangeFilterFunction失败:抛出IllegalArgumentException异常

问题:JUnit测试中WebClient构建抛出IllegalArgumentException

异常信息

java.lang.IllegalArgumentException: ExchangeFilterFunction must not be null
at org.springframework.util.Assert.notNull(Assert.java:201)
at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.filter(DefaultWebClientBuilder.java:197)
at com.mt.common.webclient.WebClientHelper.webClientBuilder(WebClientHelper.java:327)
at com.mt.common.webclient.WebClientHelper.performWebRequest(WebClientHelper.java:293)
at com.mt.common.webclient.WebClientHelper.getAsynchronousWebClient(WebClientHelper.java:62)
at com.mt.common.webclient.test.WebClientHelperTest.testGetAsynchronousWebClientWithPathParamNotNull(WebClientHelperTest.java:216)
// 省略后续栈跟踪内容

相关代码

JUnit测试代码

@Test
void testGetAsynchronousWebClientWithPathParamNotNull() throws Exception {
    WebClientHelper<Stores> helper = new WebClientHelper<Stores>();
    when(webClientRequest.getRequestTracker()).thenReturn("requesttracker");
    when(webClientRequest.getPathParam()).thenReturn("pathParam");
    when(webClientRequest.getEndPoint()).thenReturn("URL");
    Map<String, String> queryParam = new LinkedHashMap<String, String>();
    queryParam.put("Query", "select * from Stores");
    when(webClientRequest.getContentType()).thenReturn(ContentType.APPLICATION_JSON.toString());
    Map<String, String> headerParam = new LinkedHashMap<String, String>();
    queryParam.put("User", "mtamp");
    when(webClientRequest.getHeadersParam()).thenReturn(headerParam);
          ClientRequest clientRequest = Mockito.mock(ClientRequest.class);
            ExchangeFunction exchangeFunction = Mockito.mock(ExchangeFunction.class);
            ClientResponse clientResponse = mock(ClientResponse.class);
    when(webClientFilter.filter(clientRequest,exchangeFunction)).thenReturn(Mono.just(clientResponse));
    
    assertNotNull(helper.getAsynchronousWebClient(webClientRequest, Stores.class));

    verify(webClientRequest, times(1)).getRequestTracker();
    verify(webClientRequest, times(2)).getHeadersParam();
    verify(webClientRequest, times(1)).getEndPoint();
    verify(webClientRequest, times(3)).getContentType();
    verify(webClientRequest, times(2)).getPathParam();

}

WebClientHelper.java

@Autowired
WebClientFilter webClientFilter;

private WebClient webClientBuilder() {
    HttpClient httpClient = HttpClient.create()
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, WebClientConstants.WEB_CLIENT_TIMEOUT)
            .responseTimeout(Duration.ofMillis(WebClientConstants.WEB_CLIENT_RESPONSE_TIMEOUT))
            .doOnConnected(conn -> conn
                    .addHandlerLast(
                            new ReadTimeoutHandler(WebClientConstants.WEB_CLIENT_READ_TIMEOUT, TimeUnit.MILLISECONDS))
                    .addHandlerLast(new WriteTimeoutHandler(WebClientConstants.WEB_CLIENT_WRITE_TIMEOUT,
                            TimeUnit.MILLISECONDS)));
    return WebClient.builder()
             .filter(webClientFilter).filter(
                    ExchangeFilterFunction.ofResponseProcessor(this::errorHandler))
            .clientConnector(new ReactorClientHttpConnector(httpClient)).build();

}

WebClientFilter.java

@Component
public class WebClientFilter implements ExchangeFilterFunction {


@Autowired
MtExchangeFilterFunction exchangeFilter;

    
@Override
public Mono<ClientResponse> filter(ClientRequest clientRequest, ExchangeFunction next) {
    return exchangeFilter.filter(clientRequest, next);
    
}

原因分析

  • 依赖注入失效:测试中直接通过new WebClientHelper<Stores>()创建实例,Spring的@Autowired注解无法生效,导致webClientFilter字段为null。
  • 空参数触发断言:webClientBuilder()方法调用.filter(webClientFilter)时,传入的webClientFilter为null,触发Spring的非空校验断言,抛出异常。

解决方法

方法1:使用Spring Test上下文注入依赖

将测试类改为Spring Boot测试,让Spring自动管理依赖注入:

@SpringBootTest
class WebClientHelperTest {
    @Autowired
    private WebClientHelper<Stores> helper;
    
    @MockBean
    private WebClientRequest webClientRequest;
    
    @MockBean
    private WebClientFilter webClientFilter;
    
    @Test
    void testGetAsynchronousWebClientWithPathParamNotNull() throws Exception {
        when(webClientRequest.getRequestTracker()).thenReturn("requesttracker");
        when(webClientRequest.getPathParam()).thenReturn("pathParam");
        when(webClientRequest.getEndPoint()).thenReturn("URL");
        Map<String, String> queryParam = new LinkedHashMap<>();
        queryParam.put("Query", "select * from Stores");
        when(webClientRequest.getContentType()).thenReturn(ContentType.APPLICATION_JSON.toString());
        Map<String, String> headerParam = new LinkedHashMap<>();
        headerParam.put("User", "mtamp");
        when(webClientRequest.getHeadersParam()).thenReturn(headerParam);
        
        ClientRequest clientRequest = Mockito.mock(ClientRequest.class);
        ExchangeFunction exchangeFunction = Mockito.mock(ExchangeFunction.class);
        ClientResponse clientResponse = Mockito.mock(ClientResponse.class);
        when(webClientFilter.filter(clientRequest, exchangeFunction)).thenReturn(Mono.just(clientResponse));
        
        assertNotNull(helper.getAsynchronousWebClient(webClientRequest, Stores.class));

        verify(webClientRequest, times(1)).getRequestTracker();
        verify(webClientRequest, times(2)).getHeadersParam();
        verify(webClientRequest, times(1)).getEndPoint();
        verify(webClientRequest, times(3)).getContentType();
        verify(webClientRequest, times(2)).getPathParam();
    }
}

方法2:手动注入Mock过滤器

不依赖Spring上下文,通过反射或Setter方法给WebClientHelper注入Mock实例:

@Test
void testGetAsynchronousWebClientWithPathParamNotNull() throws Exception {
    WebClientHelper<Stores> helper = new WebClientHelper<>();
    WebClientFilter mockFilter = Mockito.mock(WebClientFilter.class);
    
    // 通过反射注入私有字段
    Field filterField = WebClientHelper.class.getDeclaredField("webClientFilter");
    filterField.setAccessible(true);
    filterField.set(helper, mockFilter);
    
    // 原测试逻辑
    when(webClientRequest.getRequestTracker()).thenReturn("requesttracker");
    // ... 其他Mock逻辑
    
    ClientRequest clientRequest = Mockito.mock(ClientRequest.class);
    ExchangeFunction exchangeFunction = Mockito.mock(ExchangeFunction.class);
    ClientResponse clientResponse = Mockito.mock(ClientResponse.class);
    when(mockFilter.filter(clientRequest, exchangeFunction)).thenReturn(Mono.just(clientResponse));
    
    assertNotNull(helper.getAsynchronousWebClient(webClientRequest, Stores.class));
    
    // 原校验逻辑
}

方法3:改用构造方法注入依赖

修改WebClientHelper,通过构造方法注入webClientFilter,方便测试时直接传入Mock:

public class WebClientHelper<T> {
    private final WebClientFilter webClientFilter;
    
    @Autowired
    public WebClientHelper(WebClientFilter webClientFilter) {
        this.webClientFilter = webClientFilter;
    }
    
    // 原webClientBuilder等方法
}

测试时直接传入Mock实例:

@Test
void testGetAsynchronousWebClientWithPathParamNotNull() throws Exception {
    WebClientFilter mockFilter = Mockito.mock(WebClientFilter.class);
    WebClientHelper<Stores> helper = new WebClientHelper<>(mockFilter);
    
    // 原测试逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:18:04