当前位置: 首页 > 知识库问答 >
问题:

何时使用mockito.verify()?

计燕七
2023-03-14

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

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

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

我在找:

>

  • 适当使用mockito.verify()的指导原则是什么?

    jUnits知道或紧密耦合到被测试类的实现,这在根本上是正确的吗?

  • 共有3个答案

    琴元凯
    2023-03-14

    这是个好问题!我认为其根本原因如下,我们使用JUnit不仅仅是为了单元测试。所以这个问题应该分成两部分:

    • 在集成(或任何其他高于单元测试)测试中是否应该使用mockito.verify()?
    • 是否应该在黑盒单元测试中使用mockito.verify()?
    • 我是否应该在白盒单元测试中使用mockito.verify()?

    因此,如果我们忽略高于单元的测试,那么问题可以重新表述为“使用白盒单元测试和mockito.verify()在单元测试和我的could实现之间创建了很好的耦合,我是否可以做一些”灰盒“单元测试以及我应该使用什么经验规则”。

    现在,让我们一步一步地完成这一切。

    *-我是否应该在集成(或任何其他高于单元测试)测试中使用mockito.verify()?*我认为答案显然是否定的,而且您不应该为此使用mocks。您的测试应该尽可能接近实际应用。您正在测试完整的用例,而不是应用程序的孤立部分。

    *黑盒与白盒联合测试*如果您正在使用黑盒方法,您真正在做什么,您提供(所有等价类)输入,一个状态,以及您将收到预期输出的测试。在这种方法中,通常使用模拟是合理的(您只是模拟它们正在做正确的事情;您不想测试它们),但是调用mockito.verify()是多余的。

    如果你正在使用白盒方法,你真正在做什么,你正在测试你的单位的行为。在这种方法中,调用mockito.verify()是必不可少的,您应该验证您的单元的行为是否符合您的预期。

    灰盒测试的经验法则白盒测试的问题是它会产生高耦合。一个可能的解决方案是进行灰盒测试,而不是白盒测试。这是一种黑盒和白盒测试的组合。您实际上是在测试您的单元的行为,就像白盒测试一样,但通常情况下,如果可能,您会使它与实现无关。当它可能的时候,你只需要做一个检查,就像在黑盒的情况下,只是断言输出是你所期望的。所以,你的问题的实质是什么时候是可能的。

    这真的很难。我没有一个好的例子,但我可以给你举个例子。在上面提到的equals()vs equalsIgnoreCase()的情况下,您不应该调用mockito.verify(),只需要断言输出。如果你做不到,把你的代码分解成更小的单元,直到你能做到为止。另一方面,假设您有一个@service,并且您正在编写@Web-service,它实质上是您的@service的包装器-它将所有调用委托给@service(并进行一些额外的错误处理)。在这种情况下,调用mockito.verify()是必不可少的,您不应该重复您对@servive所做的所有检查,验证您调用@service时使用了正确的parammeter列表就足够了。

    荀辰钊
    2023-03-14

    David的回答当然是正确的,但并不能很好地解释你为什么要这样做。

    基本上,当单元测试时,您是在孤立地测试一个功能单元。测试输入是否产生预期的输出。有时,你也要测试副作用。简而言之,verify允许您这样做。

    例如,您有一些业务逻辑,应该使用DAO存储东西。您可以使用一个集成测试来实现这一点,该测试实例化DAO,将其与业务逻辑挂钩,然后在数据库中四处查看预期的内容是否已存储。那不再是单元测试了。

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

    像这样的单元测试的另一个方面是,您确实将测试与实现绑定在一起,这使得重构更加困难。另一方面,一个好的设计气味是它所需要的代码量,以适当地行使它。如果您的测试需要很长时间,那么可能是设计出了问题。所以有很多副作用/复杂交互需要测试的代码可能不是一件好事。

    张炳
    2023-03-14

    如果类A的契约包括它调用类型C的html" target="_blank">对象的方法B,那么您应该通过创建类型C的模拟来测试这一点,并验证方法B已经被调用。

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

    这对于单元测试来说是正常的。当您进行单元测试时,您希望确保每个单元都在做“正确的事情”,而这通常将包括它与其他单元的交互。这里的“单位”可能是指类,或者更大的应用程序子集。

    更新:

    我觉得这不仅适用于验证,也适用于固结。从某种意义上说,一旦您存根collaborator类的方法,您的单元测试就变得依赖于实现。这是单元测试的本质。由于Mockito不仅是关于验证,而且也是关于固执的,因此使用Mockito的事实意味着您将遇到这种依赖关系。

    以我的经验,如果我改变一个类的实现,我经常不得不改变它的单元测试的实现来匹配。不过,通常情况下,我不需要更改类的单元测试清单;当然,除非更改的原因是存在一个我先前未能测试的条件。

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

     类似资料:
    • 问题内容: 我一直在nodejs中编程,研究了如何同时使用socket.io和对节点服务器的ajax调用。socket.io是否设计为替代ajax?我很好奇,在哪种情况下使用socket.io更好,而哪种ajax更好。感谢您的输入。 问题答案: 好吧,Web套接字(通过socket.io)提供的主要内容之一就是ajax缺乏的是服务器推送。因此,对于ajax,如果您想了解服务器上的新事件(例如,另一

    • 我和我的团队一直在使用Spring boot开发一系列微服务。由于服务经历了JUnit和Spring Boot升级(我们现在使用的是Spring Boot 2和JUnit 5),不同开发人员实现的不同JUnit现在使用不同的模式: @扩展为 今天,它们之间的区别是什么?我们真的需要它们来进行单元测试还是嵌入到一些新的Spring Boot注释中?

    • 问题内容: 我得到了asyncio在Python 3.5 中使用的流程,但是我还没有看到关于我应该使用什么东西,我不应该使用的await东西或者它在哪里容易出现的描述。我是否仅需要根据“这是IO操作并应进行await编辑” 来做出最好的判断? 问题答案: 默认情况下,所有代码都是同步的。你可以使用使其异步定义函数,async def并使用来“调用”这些函数await。一个更正确的问题是“什么时候应

    • 问题内容: 我感觉好像总是被教导要使用s,并且我经常看到它们与s 混合使用,以在应该在不同页面上执行相同操作的几段代码中完成相同类型的查询。开始: 那就是我正在从事的工作: 我看到很多像: 似乎LEFT也可能是INNER,有没有抓住的机会? 问题答案: 有收获吗?是的-左联接是外联接的一种形式,而内联接是内联接的一种形式。 这是显示差异的示例。我们将从基本数据开始: 在这里,我们将看到内部联接和左

    • 问题内容: 定制JPA映射器类具有以下方法: 如果我正确理解clear(),它将从上下文中删除所有持久性实体。-资源 但是,我也在这里阅读, 关于何时调用clear()的明确准则是什么? 问题答案: 文章对此进行了解释。清除实体管理器将清空其关联的缓存,从而迫使新的数据库查询在事务中稍后执行。使用事务绑定的实体管理器时,几乎几乎不需要清除实体管理器。我看到有两个原因需要清除: 在进行批处理时,为了

    • 自定义JPA映射器类有一个方法: 如果我正确理解clear(),它将从上下文中删除所有持久实体-来源 然而,我也在这里读到, 关于何时调用 clear() 的明确准则是什么?