昂贵的维护与自动化测试数据

Expensive maintenance with automated test data

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

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

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

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

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

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

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

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

  • 每个测试都可以非常明确地说明 运行 测试需要哪些数据。对于有时介于可选关联和延迟加载之类的领域模型,可能无法确定加载哪些对象。 (这里我特别想到 Hibernate,其中很多时候映射的结果可能很复杂。)相比之下,如果数据以更声明的方式设置,说明哪些行进入什么 table,开始状态是明确的。

保持测试简单、明确并且与其他部分的耦合最少意味着需要解决的问题更少,出错的可能性也更少。如果您的测试变得如此复杂,以至于与测试相比,被测代码更不可能出现任何问题,那么人们就会对运行宁和更新测试感到气馁。

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

测试数据可能会变得支离破碎且难以更新,尤其是在没有考虑重用的情况下以临时方式创建的情况下。您可能会考虑返回测试并将测试设置数据分解成可以重复使用的部分。

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

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

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

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

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