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

如何模拟带泛型通配符的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)

问题原因

  1. 参数匹配逻辑错误:测试中用Mono.just(anyString())匹配第一个参数,但实际代码传入的是Mono.just(Collections.emptyList()),类型不匹配导致Mockito找不到对应Stub, fallback到之前的null参数Stub。
  2. ParameterizedTypeReference实例不匹配:它是匿名内部类,每个实例都是独立对象,直接用eq()匹配实例会失败。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 22:13:11