【问题标题】:Mocking for integration tests模拟集成测试
【发布时间】:2012-04-25 06:43:15
【问题描述】:

如何模拟集成测试所需的众多依赖项?

我使用 Mockito 进行“纯”单元测试。在这种情况下,“纯”意味着测试单个类,模拟它的所有依赖项。漂亮。

现在进行集成测试。假设在这种情况下,集成测试将测试如下内容:

  1. 消息被放入队列
  2. 消息已“处理”
  3. 响应消息被放入响应队列

我们还可以说,第 2 步中发生的处理是严肃的事情。它依赖于大量的数据库交互、多个外部服务、文件系统以及各种各样的东西。流程还会触发很多副作用,所以我不能简单地确保响应正确 - 我需要验证副作用。

这些依赖项中的每一个都由单个无状态服务类包装,这使它们变得美观且可模拟。

人们是如何处理这个问题的?

我很想使用 Mockito 来验证上述流程的副作用。然而,Mocktio 的文档(在很大程度上是它的实现)似乎强烈反对在“纯”单元测试以外的上下文中使用它。我试过走这条路,但是

  • 很难填充存根数据(因为它有很多)
  • 很难让 Spring 将这些存根实例注入到我的 bean 中
  • 很难“重置”模拟,这样我就可以在不清除存根的情况下验证一组不同的交互。

编辑

我知道我可以使用 HSQLDB 实例之类的东西来处理数据库问题,但仍然存在外部服务的问题。为了可重复性,我不能依赖这些服务处于启动状态、处于我需要的状态等。我看到的唯一选择是模拟它们。

做什么?

【问题讨论】:

  • 只是为了澄清,因为集成测试可以通过两种方式进行。听起来您的意思是集成测试,即测试连接的组件是否可以很好地协同工作(本质上是测试 API)。但是,有时集成是指端到端的,因此您不会模拟您的服务并实际上允许它访问数据库。这种澄清可以帮助回答..请参阅stackoverflow.com/questions/4904096/…以进一步澄清类型
  • 它确实适用于任何需要大量外部依赖的测试(集成或端到端)。例如,我可以用 HSQLDB 实例替换我的数据库存根,但我仍然拥有所有其他服务。将稍微编辑问题以澄清..
  • 那么你最终是如何解决模拟问题的?

标签: mocking integration-testing mockito


【解决方案1】:

好问题。

您似乎达到了 Mockito 的极限。如果您想检查对象交互,Mockito 非常棒。

不过,您想要的似乎是更高抽象级别的可观察性(和可控性)。恐怕您需要的模拟或存根应该经过精心设计和手工制作。

在单元级别,可以通过 Mockito 很好地生成这些模拟。在集成级别,这变得更加困难,您将需要专门设计的可测试性接口。

【讨论】:

  • 是的,这听起来像是在集成级别的人们“充分利用它”,要么通过模拟库尽其所能,要么通过实际访问服务/数据库的测试实例。我目前正在开发一个基于 Groovy 的 Mockito 扩展,以帮助集成测试不那么痛苦。
【解决方案2】:

为了模拟数据库、Web 服务、文件系统等内容,您可能需要进行一些重构。对于每个外部服务,您应该编写一个包装类,该类为您希望执行的每个操作提供一个方法。每个这样的方法都应该没有实际的逻辑,而只是以外部服务将理解的方式传递其参数,并返回一个包含外部服务返回的任何数据的对象。例如,如果您正在与数据库交互,包装类可能会将其参数格式化为 SQL 语句,将它们提交到现有的 Connection 对象中,并为结果返回 List

因为包装类的方法不包含逻辑(即没有if/else,没有循环,也没有异常处理);无需对包装类进行单元测试。您应该对包装类进行集成测试,以确保其职责正确执行(例如,SQL 语句对数据库具有预期的效果)。

现在重新编写与外部服务交互的类,以便它们与包装类交互。然后很容易对它们进行单元测试——你只需要模拟包装类。

【讨论】:

  • 谢谢大卫。我的外部服务被很好地抽象出来了——每个服务都用一个 Spring 单例服务类包装。即使这样,对于复杂的场景,模拟也变得很困难。有很多数据需要存根,通常会多次调用相同的服务方法,这意味着我需要让存根返回多个值,然后是让那些注入 Spring 的问题......变得毛茸茸的。我不得不假设人们已经以更清洁的方式解决了这个问题
  • 它们必须用单例包装吗?众所周知,单身人士很难模拟。你能设计一些东西让包装器不是单例吗?
  • 另外,我会询问为什么在一次测试中多次调用相同的服务方法。也许你的测试方法太大了?我坚信“每个测试方法一个断言”规则;它确实可以进行更清洁的测试。
  • Re: 单例 - 它们是由 spring 注入的,而不是旧的 'static getInstance()' 类型。这实际上使它们非常容易测试。看到这个:stackoverflow.com/a/2302246/295797。此外,这篇文章的目的正是为了处理大型测试。我有一套小型的“每个测试方法一个断言”测试,但现实情况是复杂系统中的集成测试会多次调用同一个服务方法。
  • 抱歉,您确实提到这是一个大型集成测试。所以忽略我对每个测试一个断言的评论。我的经验是,Mockito 非常适合大型集成测试。我假设您知道如何让 Mockito 在对同一模拟方法的连续调用中做不同的事情?很抱歉我无法提供更多帮助。
【解决方案3】:

如果有一些 http 或 rest mock 框架,使用它应该是好的。

所有复杂的依赖都可以记录、修改和回放。

【讨论】:

    猜你喜欢
    • 2017-01-23
    • 1970-01-01
    • 2020-12-16
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-12
    相关资源
    最近更新 更多