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

如何根据参数的泛型类型Mock函数以返回不同值?

问题描述

我有一个接收String和TypeReference两种参数的泛型方法:

public <T> T getConfiguration(@NonNull final String configName,
                             @NonNull final TypeReference<T> typeReference) {
        return mapper.readValue(configString, typeReference);
}

编写测试时,希望传入TypeReference<Map<String, List<String>>>时返回a,传入TypeReference<Map<String, FeatureLaunchStatus>>时返回b,于是编写了如下Mock代码:

Mockito.when(mapper.readValue(Mockito.eq(SDK_BYTES), Mockito.<TypeReference<Map<String, List<String>>>>any()))
        .thenReturn(a);
Mockito.when(mapper.readValue(Mockito.eq(SDK_BYTES), Mockito.<TypeReference<Map<String, FeatureLaunchStatus>>>any()))
        .thenReturn(b);

但实际两种调用场景都返回b,替换成ArgumentMatchers也存在同样问题,需要实现不同TypeReference类型对应不同返回值的正确Mock方式。

解决方案

问题根源是Java泛型擦除机制,运行时TypeReference的泛型类型信息会被擦除,Mockito的any()匹配器无法区分不同泛型参数的TypeReference实例,第二个when语句会覆盖第一个的配置,导致所有调用都返回最后设置的b。

以下是三种可行的解决方式:

方式1:自定义ArgumentMatcher匹配TypeReference的实际类型

TypeReference通过内部逻辑保留了泛型的实际类型信息,可通过getType()方法获取,据此自定义匹配器:

// 自定义匹配器类
class TypeReferenceMatcher<T> implements ArgumentMatcher<TypeReference<T>> {
    private final Type expectedType;

    public TypeReferenceMatcher(Type expectedType) {
        this.expectedType = expectedType;
    }

    @Override
    public boolean matches(TypeReference<T> argument) {
        return argument.getType().equals(expectedType);
    }
}

// 测试中使用自定义匹配器
Mockito.when(mapper.readValue(Mockito.eq(SDK_BYTES), 
    Mockito.argThat(new TypeReferenceMatcher<>(new TypeReference<Map<String, List<String>>>(){}.getType()))))
    .thenReturn(a);

Mockito.when(mapper.readValue(Mockito.eq(SDK_BYTES), 
    Mockito.argThat(new TypeReferenceMatcher<>(new TypeReference<Map<String, FeatureLaunchStatus>>(){}.getType()))))
    .thenReturn(b);

方式2:直接匹配测试中使用的TypeReference实例

如果测试代码中是固定创建TypeReference实例传入方法,可以直接匹配该实例:

// 预先定义测试用的TypeReference实例
TypeReference<Map<String, List<String>>> listTypeRef = new TypeReference<>(){};
TypeReference<Map<String, FeatureLaunchStatus>> statusTypeRef = new TypeReference<>(){};

// 针对实例进行Mock
Mockito.when(mapper.readValue(Mockito.eq(SDK_BYTES), Mockito.eq(listTypeRef)))
    .thenReturn(a);
Mockito.when(mapper.readValue(Mockito.eq(SDK_BYTES), Mockito.eq(statusTypeRef)))
    .thenReturn(b);

// 测试调用时传入上述实例
Map<String, List<String>> resultA = getConfiguration("test", listTypeRef);
Map<String, FeatureLaunchStatus> resultB = getConfiguration("test", statusTypeRef);

方式3:使用lambda简化的argThat匹配

不想自定义类的话,可直接用argThat结合lambda表达式实现类型匹配:

Mockito.when(mapper.readValue(Mockito.eq(SDK_BYTES), 
    Mockito.argThat(tr -> tr.getType().equals(new TypeReference<Map<String, List<String>>>(){}.getType()))))
    .thenReturn(a);

Mockito.when(mapper.readValue(Mockito.eq(SDK_BYTES), 
    Mockito.argThat(tr -> tr.getType().equals(new TypeReference<Map<String, FeatureLaunchStatus>>(){}.getType()))))
    .thenReturn(b);

核心思路都是利用TypeReference运行时保留的Type信息来区分不同参数,避免使用不区分类型的any()匹配器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 21:37:40