如何模拟带泛型通配符的ParameterizedTypeReference?
WebClient Mockito测试参数匹配问题解决
场景重现
实际Post方法代码
public <T, U> U post(String serviceUrl, T data, ParameterizedTypeReference<U> ref, String bearerToken) { ParameterizedTypeReference<?> parameterizedTypeReference = new ParameterizedTypeReference<List<Object>>() { }; var responseBodyMono = webClient .post() .uri(serviceUrl) .header(HttpHeaders.AUTHORIZATION, bearerToken) .header(X_CORRELATION_ID, MDC.get(X_CORRELATION_ID)) .body(Mono.just(data), parameterizedTypeReference) // 需模拟此方法 }
测试用例代码
@Mock WebClient.RequestHeadersSpec requestHeadersSpec; @Mock WebClient.RequestHeadersUriSpec requestHeadersUriSpec; @Mock WebClient.RequestBodyUriSpec requestBodyUriSpec; @Test public void testPost() { ParameterizedTypeReference<?> parameterizedTypeReference1 = new ParameterizedTypeReference<List<Object>>() {}; Mockito.when(webClient.post()).thenReturn(requestBodyUriSpec); when(requestBodyUriSpec.uri(SERVICE_URL)).thenReturn(requestBodySpec); when(requestBodySpec.header(eq(HttpHeaders.AUTHORIZATION), eq(BEARER_TOKEN))).thenReturn(requestBodyUriSpec); when(requestBodyUriSpec.header(anyString(), Mockito.isNull())).thenReturn(requestBodyUriSpec); when(requestBodyUriSpec.body(Mono.just(anyString()), eq(parameterizedTypeReference1))).thenReturn(requestHeadersSpec); // 尝试模拟 assertNotNull(webClientService.post(SERVICE_URL, Collections.emptyList(), parameterizedTypeReference, BEARER_TOKEN)); }
错误信息
org.mockito.exceptions.misusing.PotentialStubbingProblem: Strict stubbing argument mismatch. Please check: - this invocation of 'body' method: requestBodyUriSpec.body( MonoJust, ParameterizedTypeReference<T> ); -> at com.radisys.macs.cems.common.webclient.WebClientService.getResponseEntity(WebClientServiceTest.java:310) - has following stubbing(s) with different arguments: 1. requestBodyUriSpec.body(MonoJust, null); -> at com.radisys.macs.cems.common.webclient.WebClientServiceTest.testGetResponseEntity(WebClientServiceTest.java:224)
问题原因
- 参数匹配逻辑错误:测试中用
Mono.just(anyString())匹配第一个参数,但实际代码传入的是Mono.just(Collections.emptyList()),类型不匹配导致Mockito找不到对应Stub, fallback到之前的null参数Stub。 ParameterizedTypeReference实例不匹配:它是匿名内部类,每个实例都是独立对象,直接用eq()匹配实例会失败。- Stub类型链混乱:测试中混用
requestBodySpec和requestBodyUriSpec,比如header()调用后错误切换返回类型,导致后续方法调用的Mock对象不匹配。
解决方案
方案1:修正参数匹配与Stub链
调整匹配逻辑,确保类型链正确:
@Test public void testPost() { Mockito.when(webClient.post()).thenReturn(requestBodyUriSpec); // 确保uri返回正确的RequestBodySpec类型 when(requestBodyUriSpec.uri(SERVICE_URL)).thenReturn(requestBodySpec); // header调用后保持返回RequestBodySpec,不要切换类型 when(requestBodySpec.header(eq(HttpHeaders.AUTHORIZATION), eq(BEARER_TOKEN))).thenReturn(requestBodySpec); when(requestBodySpec.header(eq(X_CORRELATION_ID), anyString())).thenReturn(requestBodySpec); // 匹配任意Mono和任意ParameterizedTypeReference when(requestBodySpec.body(any(Mono.class), any(ParameterizedTypeReference.class))).thenReturn(requestHeadersSpec); assertNotNull(webClientService.post(SERVICE_URL, Collections.emptyList(), new ParameterizedTypeReference<List<Object>>() {}, BEARER_TOKEN)); }
方案2:严格匹配泛型结构
如果需要精准匹配List<Object>类型的ParameterizedTypeReference,自定义匹配器:
private ArgumentMatcher<ParameterizedTypeReference<?>> isListOfObject() { return ref -> { Type type = ref.getType(); return type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(List.class) && ((ParameterizedType) type).getActualTypeArguments()[0].equals(Object.class); }; }
在Stub中使用:
when(requestBodySpec.body(any(Mono.class), argThat(isListOfObject()))).thenReturn(requestHeadersSpec);
方案3:重置Mock避免跨测试Stub污染
错误提示中提到的旧Stub可能来自其他测试,添加重置逻辑:
@BeforeEach void setUp() { Mockito.reset(webClient, requestBodyUriSpec, requestBodySpec, requestHeadersSpec); }
也可以临时开启宽松模式排查问题(不推荐长期使用):
@MockitoSettings(strictness = Strictness.LENIENT) public class WebClientServiceTest { // 测试代码 }
关键注意点
- WebClient的Spec类型必须严格对应:
post()返回RequestBodyUriSpec,uri()返回RequestBodySpec,header()调用后仍返回RequestBodySpec,body()返回RequestHeadersSpec。 ParameterizedTypeReference是匿名类,不能通过实例相等匹配,必须用类型或泛型结构匹配。- 测试中传入的参数类型要和实际代码保持一致,避免跨类型匹配错误。
内容的提问来源于stack exchange,提问作者New User
相关产品推荐
相关产品推荐

