测试Optional.map()逻辑时Mockito验证失败,是框架本身的Bug吗?
问题原因与解决方案
首先明确结论:这不是Mockito的Bug,是对Java Optional API的特性理解偏差导致的问题。
根本原因
Java中Optional的orElse()方法的参数是提前求值的,无论Optional实例是否为空,orElse()的入参都会被先执行计算。
你现有的业务代码中,哪怕input不为空、client.getCalendars()返回了有效结果,orElse(repository.fetch())里的repository.fetch()仍然会被调用,只是最终返回的是map操作的结果而已,所以单元测试中verify(repository, never()).fetch()的校验逻辑必然失败。
修复方案
把业务代码中的orElse替换为orElseGet即可,orElseGet接收Supplier类型的参数,只有当Optional为空时才会执行对应的逻辑,非空场景下不会触发repository.fetch()调用。
修改后的业务代码
List<Calendar> fetch(String input) { return Optional.ofNullable(input) .map(client::getCalendars) .orElseGet(() -> repository.fetch()); }
验证说明
你可以在repository.fetch()方法中增加打印日志或者断点调试,就能验证原有代码在input不为空的场景下确实会额外执行一次repository.fetch(),替换为orElseGet后该额外调用就会消失,单元测试即可正常通过。
内容的提问来源于stack exchange,提问作者Phuong Tran
相关产品推荐
相关产品推荐

