更改数据库模式&单元测试

时间:2009-08-28 09:55:50

标签: java unit-testing dbunit

在我们开始之前,我知道很少有人认为测试数据库不是“单元测试”。也许“集成测试”会是一个更好的名称。无论哪种方式,开发人员都会对数据库进行测试。

要启用单元测试,我有一个开发人员本地数据库,我清除并使用dbUnit在每次测试开始时填充一组已知数据。这一切都运行良好,直到测试使用的表以某种方式更改,我必须手动更新所有XML数据集。这是一种痛苦。我认为其他人必须遇到同样的问题,并希望找到一个很好的解决方案。因此,对于需要填充数据库的测试,您使用了什么以及如何处理表定义更改? (虽然我使用Java,但我对使用不同技术的解决方案持开放态度。)

修改 澄清一点。我有一个人为的测试:

void testLoadRevision() {
    database.clear(); // Clears every table dbUnit knows about.
    database.load("load/trevision.xml", "load/tissue.xml");
    SomeDatabaseThingie subject = new SomeDatabaseThingie(databaseProvider);
    Revision actual = subject.load();
    assert(actual, expected);
}

我有两张桌子 - tRevision和tIssue。加载的修订版使用来自tIssue的少量数据。后来tIssue获得了一个新的领域,修改不关心。由于新字段“not null”且没有合理的默认值,因此测试将失败,因为tIssue.xml将无效。

通过这样的小改动,编辑tIssue并不困难。但是当XML文件的数量随着每个流开始出现时,它就变成了大量的工作。

干杯,
MLK

3 个答案:

答案 0 :(得分:3)

我认为这个问题的答案有两个阶段:

架构只有一个权威定义

数据库的外观应该只有一个定义。在正常情况下,我更喜欢使用SQL DDL脚本来指定数据库的模式。

单元测试应该使用与应用程序使用的数据库模式相同的权威定义,应该在测试运行之前根据该定义创建数据库,并在测试运行后再次完全删除它

也就是说,工具可能与架构不同步,您将手动需要更新工具生成的内容。例如,我使用Entity Framework for .NET,它根据数据库模式自动生成类。当我更改架构时,我需要手动告诉我的工具更新这些类。这很痛苦,但我不知道有什么办法,除非工具支持自动化。

每项测试都应以空数据开头

每个测试都应该从没有任何数据的数据库开始。每个测试都应该只填充 执行测试所需的数据,一旦完成,它应该再次清理数据库。

您当前正在做的事情听起来像一个名为General Fixture的反模式,您尝试预加载一组代表尽可能广泛的场景的数据。但是,如果在某些测试中修改此预加载数据,则很难测试互斥条件,也可能导致测试相互依赖。

在优秀的书xUnit Test Patterns中已经很好地解释了这一点。

答案 1 :(得分:3)

嗯,正如我所看到的,这是一个将现有的东西结合起来的问题。

上述情景:

  1. 编写数据库迁移
  2. 应用数据库迁移(在测试运行开始时手动或自动)
  3. 由于违反约束(非空)而观察您的测试中断
  4. 您可以扩展它,以便您执行以下操作的小程序:

    1. 使用DbUnit XML
    2. 填充数据库
    3. 应用数据库迁移
    4. 在DbUnit XML(以及可选的DTD)中就地提取数据库的内容(请参阅DbUnit主页 - > DbUnit常见问题 - >如何从我的数据库中提取平面XML数据集?)
    5. 将更新的DbUnit XML(和DTD)检查到源代码管理中。
    6. 为了应用迁移,我衷心建议Flyway。它支持Sql(带占位符替换)和基于Java的迁移。然后,您可以使用Maven插件应用迁移,或使用API​​以编程方式应用迁移。后者非常适合这种情况。

      然后完整的工作流程变为:

      1. 编写数据库迁移
      2. 执行您的DbUnitXmlDtdUpdater计划
      3. 观看您的单元测试通过
      4. 快乐的日子,

        阿克塞尔

        免责声明:我是Flyway的开发人员之一。

答案 2 :(得分:2)

我遇到了同样问题的dbunit xml平面文件在数据库模式演变时运行不同步,这需要更改数据(即使是添加强制列这样简单的事情)。

虽然使用一些手写脚本转换所有xml文件是一种选择,但我仍然认为问题应该在不同的抽象级别解决,更类似于处理实时数据的方式:进化数据库设计。

数据库迁移工具已经了解delta脚本,因此使用某种dbunit适配器会很棒。

如果发现以下博客文章涉及该问题: http://blog.liquibase.org/2007/06/unit-testing-the-database-access-layer.html

  

要解决使测试数据定义与模式不同步的问题,您需要将测试数据与数据库一起构建,以便通过最初创建后的数据库重构来修改它。 [..]通过将测试数据与数据库更改一起包含,数据将自动保持与生产数据相同的方式。在每个方法的数据集上使用这种技术还具有表现更好的优点,因为数据只插入一次,......

但是自己补充道:

  

但它的缺点是你需要在一个地方处理任何方法所需的所有测试数据。

...我认为这对于更复杂的场景来说是不可能的。他继续说:

  

为了促进这种技术,我将执行上下文的思想构建到LiquiBase中,以便您可以标记测试数据更改并仅在运行单元测试的环境中应用它们。到目前为止,我对结果感到满意。当数据库模式与代码期望的差异或我的SQL中存在错误并且由于数据库重构而没有丢失任何测试时,测试失败。

这里是链接:www.liquibase.org/manual/contexts但它不是我想要的,尽管我可以将我的testdata暴露给数据库迁移工具,我还是希望它能保持非常接近数据库测试。

有人想到吗?