12

在我的公司,我们在 Java Web 应用程序中使用 JUnit 进行了越来越多的集成测试。每个测试都使用一些特定的外部 XML 文件来使用测试所需的数据填充数据库。问题是:

  1. 当模型发生变化时,我们需要很长时间来更正所有 XML 文件(我们有数百个 XML 文件,其中很多是冗余的)。
  2. 手动创建 XML 文件的复杂性阻碍了程序员探索不同的场景。
  3. 我们在测试数据和测试之间没有链接(例如,在测试中我不知道 XML 插入的用户的“名称”)。我们可以硬编码我们需要的信息,但它也会增加维护时间以保持 XML 和硬编码数据同步。

面对这个问题,我开始考虑使用自己的系统 CRUD 来为每个测试生成测试数据。在每个测试开始时,我会运行一些方法来保存测试所需的数据。在我看来,它将解决所有 3 个问题,因为:

  1. 无论如何,对模型的更改都需要更改 CRUD,因此不再需要更正测试数据。
  2. 构建、测试数据会更容易,因为我们不必担心手动匹配实体的 id 和外键之类的事情。
  3. 我将在 IDE 保证同步的变量中拥有所有重要数据。

但是,对我来说,开始这种方法缺乏经验和知识。问题是:这个解决方案有效吗?这种方法会导致其他问题吗?我在哪里可以在文献中找到这种方法?列出的问题是否有更好的解决方案?

4

2 回答 2

4

听起来您现有的系统使用 DBUnit 之类的东西,其中测试从一个干净的数据库开始,测试包括一个设置步骤,将数据从一个或多个 XML 文件加载到数据库中,然后针对该数据执行测试。

以下是这种方法的一些好处:

  • 如果您确实对 crud 层有问题,那么这不会影响数据设置。当出现问题时,每个错误都应该出现一个测试失败,而不是每个失败的相关设置都出现一个错误。

  • 每个测试都可以非常明确地明确运行测试所需的数据。有时域模型介于可选关联和延迟加载之间,加载的对象可能不确定。(在这里我特别想到了 Hibernate,其中很多时候映射的结果可能很复杂。)相比之下,如果数据以更具声明性的方式设置,说明哪些行在哪个表中,则起始状态是明确的。

保持测试简单、明确并且与其他部分的耦合最小意味着需要弄清楚的事情更少,出错的可能性也更少。如果您的测试变得如此复杂,以至于任何问题都不太可能出在被测代码上,而不是出在测试上,那么人们就会对运行和更新测试感到灰心。

使用 DBUnit,您可以编写脚本来自动从数据库内容创建 XML,因此您可以重新创建所需的状态并将其保存为 XML。不需要手动生成测试数据。

测试数据可能会变得支离破碎且难以更新,特别是如果它是以临时方式创建的,没有考虑重用。您可能会考虑回顾测试并将测试设置数据分解成可以重复使用的部分。

在我看来,您描述的痛点并不需要极端措施,例如重做所有测试设置。即使你这样做了,你仍然想重构你的测试数据。也许使用一个较小的项目作为更大更改的试验场,并对大多数现有代码进行小的增量更改。

于 2015-04-20T20:46:34.973 回答
1

提高可维护性的关键是保持 DRY。测试数据设置不应该是多余的,如果你的测试技术没有提供有效的重用方法,那么你就使用了错误的技术。

为测试数据设置编写 Java 代码为您提供了熟悉且良好的工具来改进跨测试的代码重用。它还提供比 XML 更好的重构支持,并使测试数据和测试代码之间的链接显式化,因为它们在同一个源文件中(甚至是同一个方法!)。但是,它确实需要由程序员(而不是业务分析师、经理或不懂 Java 的测试人员)编写和维护测试。

因此,如果测试数据主要由程序员编写和维护,我会在 Java 中通过实际应用程序的 CRUD 层(甚至是完整的领域层)来完成。然而,如果大多数测试数据来自某些数据导出,或者由非程序员的人创作,那么纯粹的数据驱动方法可能更合适。也可以将这些方法结合起来(即为每个实体选择最合适的策略)。

个人经验:我们的团队曾经使用 DBUnit 进行集成测试,但现在已经切换到使用我们的真实数据访问层将测试数据设置为测试代码的一部分。这样做,我们的测试变得更能揭示意图并且更容易维护。测试工作量减少了,但测试覆盖率提高了,用更少的刺激编写了更多的测试。这是可能的,因为测试完全由开发人员编写和维护。

于 2015-04-20T21:16:21.503 回答