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

