Mockito存根Spring RestTemplate时出现PotentialStubbingProblem问题
any(RequestEntity.class)无法匹配实际调用? 问题核心
你遇到的问题本质是Mockito方法重载匹配错误,以及匹配器的类型检查逻辑导致的存根不匹配。
原因分析
参数类型不匹配:
被测方法中创建的请求实体是HttpEntity<Void>,调用的是RestTemplate的exchange(String, HttpMethod, HttpEntity<?>, Class<T>, Map<String, ?>)重载方法。但你的初始测试代码中,第三个参数用了any(RequestEntity.class)——而RequestEntity是HttpEntity的子类,父类实例(HttpEntity)无法通过any(RequestEntity.class)的类型检查(该匹配器只接受RequestEntity或其子类对象),导致Mockito找不到对应的存根。Mockito错误提示的误导:
当Mockito无法匹配到对应重载的存根时,错误信息里会显示存根参数为""、null等占位符,这是它的默认提示逻辑,容易让你误以为存根本身的参数有问题,实际是存根匹配的方法重载和实际调用的重载完全不对应。泛型指定的
any()为何有效:
你修改后的ArgumentMatchers.<RequestEntity<Void>>any()本质是调用了无类型检查的any()匹配器(泛型指定只是为了消除编译警告),any()不做参数类型校验,会匹配任何非null对象,因此能匹配到实际传入的HttpEntity对象,存根也就生效了。
更严谨的修复写法
其实不需要指定泛型,直接用any(HttpEntity.class)才是最贴合实际参数类型的写法,既符合类型检查,又能准确匹配目标重载:
when(mockRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), any(Class.class), any(Map.class))) .thenReturn(new ResponseEntity<>(new HarvestAllUsers(), HttpStatus.OK));
总结
Mockito的匹配器对类型的检查是严格的,尤其是在存在多个方法重载时,一定要确保匹配器的类型和实际调用的参数类型一致,否则会导致存根匹配失败。错误提示中的空值参数只是表象,核心是重载方法匹配错误。
内容的提问来源于stack exchange,提问作者Stan Ostrovskii

