为什么要避免使用Mockito.verify?

ioekq8ef  于 5个月前  发布在  其他
关注(0)|答案(3)|浏览(77)

我的公司不允许在单元测试中使用Mockito.verify。甚至有一个定制的声纳规则。
规则如下。
结果应该通过Assert来验证,而不是使用verify来做流程验证。因为如果我们验证流程,在流程改变后需要更多的精力来维护测试,但输入和输出保持不变。确保每一行代码都对结果有影响,并Assert结果以证明逻辑是正确的。
不兼容代码示例

verify(graphics2D, times(1)).dispose();// Noncompliant

字符串
合规解决方案

assertThat(((SunGraphics2D) graphics2D).getSurfaceData()).isInstanceOf(NullSurfaceData.class);


对于数据库或中间件操作,使用嵌入式数据库或中间件Assert数据写入成功。
对于restful请求,使用wiremock的verifyAssert模拟服务器收到了相应的请求。

WireMock.verify(postRequestedFor(urlEqualTo("http://localhost:8080/query"))
                .withHeader("Content-Type", equalTo("application/json"))
                .withRequestBody(equalToJson("{" +
                        "\"testing-library\": \"WireMock\"," +
                        "\"creator\": \"Tom Akehurst\"," +
                        "\"website\": \"wiremock.org\"" +
                        "}")));


我的问题是,其他IT公司是否有类似的规则来避免在单元测试中使用Mockito.verify?这是一个好规则还是坏规则?非常感谢。

jw5wzhpr

jw5wzhpr1#

好吧,这需要一个很长的答案,但我会尽量让它变短。换个公司。它基本上是两种不同的测试。在一种情况下,你检查输入和输出(Assert),在另一种情况下,你的输出很可能是无效的,然后你只需验证函数被调用。
除此之外,您可以使用verify进行“集成测试”,在这些测试中,您希望验证函数是否被调用,并且您可能还希望使用“inOrder()”验证它们被调用的顺序,如下所述:Mockito verify order / sequence of method calls
有时单元测试和集成测试会重叠。集成测试有两个子类型:

  • 那些因为必要性而需要嘲笑的人;
  • 那些根本不使用模拟的人。

最近使用了一个maven插件,它允许在测试或验证阶段随意生成docker容器。

<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.33.0</version>

字符串
这允许您在公共Jenkins管道中运行项目内的集成测试和端到端测试。当您无法在Jenkins中使用docker时,唯一的问题出现,因为docker没有安装在运行测试的机器上。

5lwkijsr

5lwkijsr2#

没有验证的Assert只能在测试方法返回后检查结束状态。要有一个完整的结束状态,你需要有所有的真实的对象,没有mock。使用任何mock意味着你在结束时没有完整的状态,你不能检查所有你应该检查的东西而不使用verify。所以,如果禁止使用verify,那么你根本就不应该使用Mockito。而且你应该意识到你是在写集成测试而不是单元测试。
然而,集成测试不会告诉你哪里出了问题,也不会告诉你在哪里寻找根本原因:bug是在你的代码中还是在你使用的第三方库的代码中?你必须自己调查和调试才能找到答案。这就是为什么你需要真实的单元测试。
如果被测试的方法需要进行单元测试,这意味着测试应该测试该方法正在做什么,而不依赖于被调用的任何方法的实现。当被调用的方法在mock中时,发送到mock的数据通常不会去任何地方,您无法验证调用中传递的数据是否正确。然后Assert它们。但是你只是使用Assert实现了你自己的验证方法。当被调用的方法不是mock时,你的测试将依赖于该方法的实现,不再是单元测试。改变被调用方法的实现可能会破坏许多调用该方法的方法的单元测试。
或者简而言之:如果你的公司不想让你使用verify,他们不想让你写单元测试,而是集成测试。
单元测试和集成测试都是有用的,并且是互补的。如果结构良好,两者都是可维护的。但是当您混合使用两种类型时,测试变得难以维护(使用真实的对象的单元测试,而不是使用mock的集成测试)。因此,对于集成测试,避免验证(和模拟)是一个好的规则。2对于单元测试来说,这是一个坏的规则,因为它使编写真实的单元测试变得不可能。

cs7cruho

cs7cruho3#

我知道这是一个旧的线程,但我想添加我的2美分。(我是一个java开发人员,它可能会显示。)
这并不是因为你不使用mock所以你在写集成测试!你也可以使用fakes。Fakes是实现接口并提供一些标准行为的真实的对象。
例如,您可以使用PersonRepositoryFake类实现存储库PersonRepository,并实现它的3个方法:保存、查找和删除(同样,例如,对于jpa存储库,不要这样做。将其隐藏得更深)。实现将只是将这些内容存储在hashmap中,伪造数据库的行为。您可以将其插入任何测试中,而无需准备模拟的所有混乱和重构时的所有痛苦。
我明白他们为什么有这个规则,他们是对的。让我解释一下。
你想让你的测试失败,当有什么东西坏了,对吗?你不想让你的测试失败,当没有什么东西坏了。
你希望能够重构你的代码,并防止你可能引入的错误。你 * 不 * 想被你的测试惩罚,因为他们希望你对一个已经很久没有使用过的方法(或者一个已经改变的参数)进行两次特定的调用。如果你没有破坏它,这些测试就不应该失败。
当按下一个按钮,将一个“人”存储在数据库中时,你感兴趣的是一个人最终存储在数据库中(行为)。
我可以写一本关于这方面的书,但简而言之,使用真实的对象进行测试,并使用假对象进行外层(洋葱架构,如db,web,文件系统等)。我仍然容忍mock的唯一地方是在控制器中(在外层),并检查参数是否正确。在那里,我会接受mockmvc和mock的用例。
当然,我也知道有些系统并不简单。但是你在测试中指定的东西越多,你就花越多的时间来修复坏的测试(一开始就不应该坏的),而不是提高效率。这就像在你的代码上扔混凝土,所以没有人愿意再次重构它(或者受到严重的惩罚)。

相关问题