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

Mockito PotentialStubbingProblem报错:参数一致却提示不匹配

Mock RestTemplate时PotentialStubbingProblem错误排查与解决

问题场景

Mock RestTemplate测试getAvailableCurrencies方法时,通过Mockito.doReturn指定restTemplate.getForObject传入null和SymbolEndpointResponce.class作为参数,但运行时触发PotentialStubbingProblem错误,提示调用与存根参数不匹配,然而日志显示两者参数完全一致。

待测试方法代码

public HashMap<String, String> getAvailableCurrencies() {
   SymbolEndpointResponce symbolResponce = restTemplate.getForObject(this.baseUrl, SymbolEndpointResponce.class);

  System.out.println(symbolResponce);

  if(symbolResponce.getSuccess()) {
    return symbolResponce.getSymbols();
  }

  return null;
 }

测试类代码

@Test
void getAvailableCurrencies() throws URISyntaxException {

    Mockito.doReturn(getMockSymbols()).when(restTemplate)
            .getForObject(null, SymbolEndpointResponce.class);
    HashMap<String, String> symbols = service.getAvailableCurrencies();
    assertEquals(4, symbols.size());
}

private SymbolEndpointResponce getMockSymbols() {
    ...
}

报错信息(中文翻译)

org.mockito.exceptions.misusing.PotentialStubbingProblem: 
   严格存根参数不匹配,请检查:
 - 'getForObject'方法的本次调用:
    restTemplate.getForObject(
    null,
    class de.c24.finacc.klt.model.SymbolEndpointResponce
);
    -> at de.c24.finacc.klt.services.SymbolService.getAvailableCurrencies(SymbolService.java:35)
 - 以下存根使用了不同的参数:
    1. restTemplate.getForObject(
    null,
    class de.c24.finacc.klt.model.SymbolEndpointResponce
);
      -> at de.c24.finacc.klt.services.SymbolServiceTest.getAvailableCurrencies(SymbolServiceTest.java:37)
通常,存根参数不匹配表明编写测试时存在用户错误。
Mockito提前失败以便你轻松调试潜在问题。
但以下合法场景可能导致误报:
  - 使用'given().will()'或'when().then()'API多次存根同一方法
    请使用'will().given()'或'doReturn().when()'API进行存根。
  - 被测代码故意使用不同参数调用存根方法
    请使用默认或'silent'JUnit规则(等效于Strictness.LENIENT)。
更多信息请查看PotentialStubbingProblem类的javadoc。

解决方法

1. 校验baseUrl的实际值

待测试方法中调用restTemplate.getForObject时传入的是this.baseUrl,而测试存根用的是null。如果测试时service的baseUrl并未被设置为null(比如默认是空字符串、未初始化的其他值),就会导致实际调用参数和存根参数不匹配。

解决方式:

  • 测试前显式设置baseUrl为null:
    @Test
    void getAvailableCurrencies() throws URISyntaxException {
        service.baseUrl = null; // 假设baseUrl是可访问的成员变量
        Mockito.doReturn(getMockSymbols()).when(restTemplate)
                .getForObject(null, SymbolEndpointResponce.class);
        HashMap<String, String> symbols = service.getAvailableCurrencies();
        assertEquals(4, symbols.size());
    }
    
  • 或者使用参数匹配器匹配任意字符串,避免依赖具体值:
    Mockito.doReturn(getMockSymbols()).when(restTemplate)
            .getForObject(Mockito.anyString(), Mockito.eq(SymbolEndpointResponce.class));
    

2. 排查类加载器导致的Class对象不相等

虽然类名完全一致,但不同类加载器加载的SymbolEndpointResponce类会被视为不同的类型,导致SymbolEndpointResponce.class在存根和调用时不是同一个对象。

验证方式:在测试和待测试方法中分别打印SymbolEndpointResponce.class的哈希值或完整信息:

// 待测试方法中添加
System.out.println("待测试类中Class对象:" + SymbolEndpointResponce.class + ",哈希值:" + SymbolEndpointResponce.class.hashCode());

// 测试类中添加
System.out.println("测试类中Class对象:" + SymbolEndpointResponce.class + ",哈希值:" + SymbolEndpointResponce.class.hashCode());

如果两者哈希值不同,说明存在类加载器问题,需要调整测试环境的类加载配置(比如确保测试和主代码使用同一类加载器)。

3. 切换为宽松存根模式

如果确认参数确实一致,是Mockito严格模式的误判,可以启用宽松存根来绕过这个错误:

方式一:给Mock对象添加宽松设置

@Mock(strictness = Strictness.LENIENT)
private RestTemplate restTemplate;

方式二:存根时使用lenient()

Mockito.lenient().doReturn(getMockSymbols()).when(restTemplate)
        .getForObject(null, SymbolEndpointResponce.class);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 06:33:11