Mockito报WrongTypeOfReturnValue错误:自定义Actuator端点集成测试执行失败
看起来你遇到的这个Mockito错误,核心原因和两个点有关——Spy对象的Stub方式不当,或者自定义Actuator端点的返回值不符合规范,结合你的代码我来拆解一下:
一、先看Mockito错误的直接触发原因
你看到的WrongTypeOfReturnValue提示里明确提到:用when(spy.foo()).then()语法Stub Spy对象容易出问题,建议用doReturn/Throw系列方法。这大概率是因为你的restTemplate是个Spy对象(比如用@SpyBean注入的真实实例代理),而不是纯Mock对象(@MockBean)。
当你用when(restTemplate.exchange(...)).thenReturn(...)时,Mockito会先执行一次真实的exchange方法,而真实方法内部可能调用了某个toString()方法,这就触发了Mockito的类型校验错误——它误以为某个toString()应该返回String,但实际流程中返回了ResponseEntity。
快速修复Mock代码:
如果不需要依赖真实RestTemplate的行为,直接把restTemplate换成@MockBean注入;如果必须用Spy,把Stub方式改成doReturn(这种方式不会执行真实方法,直接返回你指定的对象):
doReturn(responseEntity) .when(restTemplate) .exchange(anyString(), eq(HttpMethod.GET), any(), eq(CorollaResponse.class));
二、自定义Actuator端点的返回值规范问题
你的CorollaHealthCheck端点用@ReadOperation返回了ResponseEntity<String>,这不符合Spring Boot Actuator的设计规范:Actuator的端点方法返回值会被直接序列化为响应体,而不是作为HTTP响应的包装器来处理。
当你返回ResponseEntity时,Actuator会把整个ResponseEntity对象作为响应体处理,在序列化过程中会调用它的toString()方法,这刚好和Mockito的错误触发点重合,进一步加重了问题。
修复端点代码:
把返回值改成直接返回字符串,用ResponseStatusException来处理错误状态:
@Component @Endpoint(id = "corollahealth") public class CorollaHealthCheck { @Autowired private CorollaIntegration corollaIntegration; @ReadOperation public String corollahealth() { try { CorollaResponse corollaResponse = corollaIntegration.checkCorolla(); return "Corolla OK"; } catch (Exception e) { throw new ResponseStatusException( HttpStatus.BAD_REQUEST, "Corolla couldn't be reached.\nIt may be down or there could be some other issue.\nManually check if Corolla is available." ); } } }
这样Actuator会自动根据异常设置响应状态码,响应体就是你返回的字符串,不会再触发ResponseEntity的序列化问题。
三、额外检查点:Mock参数的匹配一致性
你问题里提到的代码片段中,有一行写的是eq(CartellResponse.class),但测试代码里是eq(CorollaResponse.class)——如果实际代码中corollaIntegration.checkCorolla()调用的是CartellResponse类型,那你的Mock就不会命中,会执行真实请求导致错误。一定要确保Mock的参数类型和实际调用完全一致。
备注:内容来源于stack exchange,提问作者runnerpaul

