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

Why avoid using Mockito.verify?

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

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

合规解决方案

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

对于数据库或中间件操作,使用嵌入式数据库或中间件断言数据写入成功。

对于restful个请求,使用wiremock的verify断言mock server收到了对应的请求。

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?这是善治还是恶治?非常感谢。

好吧,这需要一个很长的答案,但我会尽量简短。 换公司。 它基本上是两种不同类型的测试。 在一种情况下,您正在检查输入和输出(断言),在另一种情况下,您的输出很可能是无效的,然后您只需验证函数是否被调用。

除此之外,您还可以在“集成测试”中使用 verify 来验证函数是否被调用,并且您可能还需要使用“inOrder()”来验证它们的调用顺序,如下所述: Mockito verify order / sequence of method calls

有时单元测试和集成测试会重叠。 集成测试有 2 种子类型:

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

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

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

这让您可以 运行 集成测试和端到端测试在您的项目中使用通用的 Jenkins 管道。当您无法在 Jenkins 中使用 docker 时出现唯一的问题,因为 docker 未安装在 运行 进行测试的机器上。

未经验证的断言只能在测试方法返回后检查结束状态。要拥有完整的最终状态,您需要拥有所有真实对象,而不是模拟对象。使用任何 mock 都意味着你最后没有完整的状态,并且你无法在不使用验证的情况下检查你应该检查的所有内容。因此,如果禁止使用验证,那么您根本不应该使用 Mockito。你应该知道你正在编写集成测试而不是单元测试。

然而,集成测试不会告诉您出了什么问题以及在哪里寻找根本原因:错误是在您的代码中还是在您使用的第三方库的代码中?您将必须自己进行调查和调试才能找到答案。这就是为什么您需要真正的单元测试。

如果被测试的方法需要进行单元测试,这意味着测试应该测试该方法在做什么,而不依赖于被调用的任何方法的实现。 当被调用的方法在模拟中时,发送到模拟的数据通常不会去任何地方,您无法验证调用中是否传递了正确的数据。您可以使用存储参数的答案对象存根该方法,然后再对它们进行断言。但是你只是使用断言实现你自己的验证方法。 当被调用的方法不是 mock 时,您的测试将取决于该方法的实现,不再是单元测试。更改被调用方法的实现可能会破坏许多调用该方法的方法的单元测试。

或者简而言之:如果你的公司不希望你使用验证,他们不希望你写单元测试,而是集成测试。

单元测试和集成测试都是有用的,并且是相辅相成的。如果结构良好,两者都是可维护的。但是当您混合使用这两种类型时(使用真实对象而不是模拟的单元测试或使用模拟的集成测试),测试变得难以维护。 因此,对于集成测试,避免验证(和模拟)是一个很好的规则。对于单元测试,这是一个糟糕的规则,因为它使得编写真正的单元测试变得不可能。