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

