我经常看到相同的方法被验证为Mockito
中被模拟的方法(下面的示例)。在这些情况下调用Mockito.verify()
会有什么额外的好处吗?
//mock method
FooService fs = mock(FooService.class);
when(fs.getFoo()).thenReturn("foo");
//method under test
fs.doSomething();
//verify method
verify(fs).getFoo();
如果未调用fs.getFoo()
,则该方法应该失败。那么为什么要打电话给verify
?如果您需要在验证中使用ArgumentCaptor
来断言参数,我会看到好处;除了ArgumentCaptor案例,它是否只是不必要的?
答案 0 :(得分:7)
Mockito文档反复说它通常是多余的。这在verify(T)
's Javadoc中逐字显示为Mockito's main class Javadoc section 2中代码块中的多个单行注释:
虽然可以验证存根调用,但通常它只是多余的。 如果您的代码关心
get(0)
返回的内容,那么其他内容会中断(通常甚至在verify()
执行之前)。 如果您的代码并不关心get(0)
返回的内容,那么它不应该被删除。不相信?请参阅here。
请注意,链接文章" Asking and Telling"由Mockito创始人Szczepan Faber编写,可以被视为Mockito设计中的权威文档。摘自该帖子:
我真的必须重复相同的表达吗?毕竟,存根交互隐式验证。我自己的代码的执行流程完全免费。 Aaron Jensen也注意到:
如果您正在验证您不需要存根,除非该方法返回对您的测试(或代码)流程至关重要的方法,在这种情况下您实际上不需要验证,因为流程已经验证。
回顾一下:没有重复的代码。
但是,如果一个有趣的交互分享询问和说明的特征会怎么样?我是否必须在stub()和verify()中重复交互?我最终会得到重复的代码吗?并不是的。在实践中:如果我存根那么它是免费验证的,所以我不验证。 如果我验证,那么我不关心返回值,所以我不存根。无论哪种方式,I don’t repeat myself。但理论上,我可以想象一个罕见的情况,我确认了一个存根交互,例如确保存根交互恰好发生了n次。但这是行为的一个不同方面,显然是一个有趣的方面。因此,我想要明确,我非常乐意牺牲一行额外的代码......
总的来说,Mockito的设计是允许测试尽可能灵活,编码不是为了实现,而是编码你正在测试的方法。虽然您偶尔会将方法调用视为函数规范的一部分("向服务器提交RPC"或者"立即调用传递的LoginCallback"),您更有可能想要验证可以从存根中推断出的后置条件:检查getFoo
被调用是否真的只是规范的一部分,只要你抄袭了getFoo
来回归" foo"并且数据存储包含一个对象,其对应的属性设置为" foo"。
简而言之,明确只验证精心设计的存根和后置条件断言无法隐含的交互被认为是良好的Mockito风格。它们可能是对其他不可测量的副作用的良好调用 - 记录代码,线程执行器,ArgumentCaptors,多个方法调用,回调函数 - 但通常不应该应用于存根交互。
答案 1 :(得分:0)
在你给出的具体例子中(这不是一个完整的例子,但它足以使你的问题清楚),我认为没有理由验证存根的电话。
我认为验证旨在产生副作用的调用以及存根调用(使用when
)是非常好的设计,这些调用旨在提供数据。在大多数情况下,两者都会使设计不那么清晰,测试的可读性也会降低。
如果提供数据且没有副作用的调用作为参数值接收,该值由被测方法生成或修改(例如,合成的键以检索值),则验证可能很有用(即使参数很简单,你不需要ArgumentCaptor
)。您可以使用特定参数或自定义匹配器存根,这可能足以测试这种情况(例如when(fs.getFoo("generatedKey1234")).thenReturn("foo1234")
),但检查verify
中的参数可以增强测试的可读性 - 所以这是一个判断电话。