何时使用 Mockito.verify()?

2022-08-31 06:10:26

我编写 jUnit 测试用例有 3 个目的:

  1. 为了确保我的代码满足所有必需的功能,请在所有(或大多数)输入组合/值下。
  2. 为了确保我可以更改实现,并依靠JUnit测试用例告诉我,我的所有功能仍然满足。
  3. 作为所有用例的文档,我的代码处理,并充当重构的规范 - 如果代码需要重写。(重构代码,如果我的jUnit测试失败 - 你可能错过了一些用例)。

我不明白为什么或何时应该使用。当我看到被调用时,它告诉我我的jUnit正在意识到实现。(因此,更改我的实现会破坏我的jUnits,即使我的功能不受影响)。Mockito.verify()verify()

我正在寻找:

  1. 正确使用 的准则应该是什么?Mockito.verify()

  2. 对于 jUnits 来说,了解或紧密耦合所测试类的实现从根本上是正确的吗?


答案 1

如果类 A 的协定包括它调用 C 类型对象的方法 B 的事实,则应通过模拟类型 C 并验证是否已调用方法 B 来对此进行测试。

这意味着类 A 的协定具有足够的细节,它谈论类型 C(可能是接口或类)。所以,是的,我们谈论的是一个超越“系统需求”的规范级别,并且在某种程度上描述了实现。

这对于单元测试是正常的。当你进行单元测试时,你要确保每个单元都在做“正确的事情”,这通常包括它与其他单元的交互。此处的“单位”可能是指类或应用程序的较大子集。

更新:

我觉得这不仅适用于验证,也适用于存根。只要你对一个协作者类的方法进行存根,你的单元测试就会在某种意义上依赖于实现。这有点像单元测试的本质。由于 Mockito 既是关于验证,也是关于 stubbing 的,因此你使用 Mockito 的事实意味着你会遇到这种依赖关系。

根据我的经验,如果我更改一个类的实现,我通常必须更改其单元测试的实现以匹配。但是,通常情况下,我不必更改类的单元测试的清单;当然,除非更改的原因是存在我之前未能测试的条件。

这就是单元测试的意义所在。一个不受这种依赖性于协作者类的使用方式的测试实际上是子系统测试或集成测试。当然,这些也经常用JUnit编写,并且经常涉及使用模拟。在我看来,“JUnit”是一个可怕的名字,对于一个让我们生产所有不同类型的测试的产品。


答案 2

大卫的答案当然是正确的,但并不能完全解释为什么你会想要这个。

基本上,在单元测试时,您正在单独测试一个功能单元。测试输入是否生成预期的输出。有时,您还必须测试副作用。简而言之,验证允许您这样做。

例如,您有一些业务逻辑,应该使用DAO来存储内容。您可以使用集成测试来执行此操作,该测试实例化DAO,将其连接到业务逻辑,然后在数据库中四处查看是否存储了预期内容。这不再是单元测试了。

或者,您可以模拟 DAO 并验证它是否以您期望的方式被调用。使用mockito,您可以验证某些内容是否被调用,它被调用的频率,甚至可以在参数上使用匹配器来确保它以特定的方式被调用。

像这样的单元测试的另一面确实是,您将测试与实现联系起来,这使得重构变得更加困难。另一方面,一个好的设计气味是正确执行它所需的代码量。如果你的测试需要很长,可能是设计出了问题。因此,需要测试的具有大量副作用/复杂交互的代码可能不是一件好事。


推荐