代码之家  ›  专栏  ›  技术社区  ›  Michael Lloyd Lee mlk

更改数据库架构和单元测试

  •  6
  • Michael Lloyd Lee mlk  · 技术社区  · 15 年前

    在我们开始之前,我知道有相当一部分人认为数据库中的测试不是“单元测试”。也许“集成测试”会是一个更好的名字。无论哪种方式,开发人员都会测试数据库。

    为了启用单元测试,我有一个开发人员本地数据库,在每个测试开始时,我清除该数据库,并使用 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);
    }
    

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

    像这样的小变化不难编辑组织。但是,当XML文件的数量开始随着每个流膨胀时,它就变成了大量的工作。

    干杯,
    MLK

    3 回复  |  直到 11 年前
        1
  •  3
  •   Axel Fontaine    11 年前

    好吧,正如我所见,这是一个结合已经存在的问题。

    上述场景:

    1. 写入数据库迁移
    2. 应用数据库迁移(在测试运行开始时手动或自动)
    3. 注意测试因违反约束而中断(非空)

    您可以将其扩展到一个执行以下操作的小程序:

    1. 用dbunit xml填充数据库
    2. 应用数据库迁移
    3. 在DBUnit XML(也可以是DTD)中提取数据库的内容(请参阅DBUnit主页->DBUnit常见问题解答->如何从我的数据库提取平面XML数据集?)
    4. 将更新后的dbunit xml(和dtd)检查到源代码管理中。

    对于应用迁移,我衷心推荐 Flyway . 它支持SQL(占位符替换)和基于Java的迁移。然后,您可以使用Maven插件或通过编程使用API应用迁移。后者完全符合这个情况。

    然后,完整的工作流变成:

    1. 编写数据库迁移
    2. 执行dbunitxmldtdupdater程序
    3. 观看单元测试通过

    快乐的日子,

    阿克塞尔

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

        2
  •  3
  •   Mark Seemann    15 年前

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

    架构只有一个权威定义

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

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

    也就是说,工具可能与模式不同步,您需要手动更新工具生成的东西。例如,我使用.NET的实体框架,它根据数据库模式自动生成类。当我更改模式时,我需要手动告诉我的工具更新这些类。这是一种痛苦,但我不知道有什么办法可以摆脱它,除非工具支持自动化。

    每个测试应该从空数据开始

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

    您当前所做的工作听起来像是一个名为“通用夹具”的反模式,您试图预加载一组数据,这些数据表示尽可能广泛的一组场景。但是,这使得测试互斥条件非常困难,并且如果在某些测试中修改这个预加载的数据,也可能导致测试相互依赖性。

    这在这本好书中解释得很清楚 xUnit Test Patterns .

        3
  •  2
  •   jonaskilian    14 年前

    我也有同样的问题,DBUnitXML平面文件在数据库模式演化时会失去同步,这确实需要数据更改(即使对于像添加强制列这样简单的事情)。

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

    数据库迁移工具已经知道delta脚本,所以拥有一种DBUnit适配器将是很好的选择。

    如果找到以下包含此问题的日志: http://blog.liquibase.org/2007/06/unit-testing-the-database-access-layer.html

    要解决使测试数据定义与模式不同步的问题,需要将测试数据与数据库一起构建,以便通过最初创建后进行的数据库重构对其进行修改。通过将测试数据包括在数据库更改中,数据将以生产数据的相同方式自动保存。在每个方法的数据集上使用这种技术还有更好的性能优势,因为数据只插入一次,…

    但他补充道:

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

    …我猜,这对于更复杂的情况是不可能的。他继续说:

    为了方便这种技术,我将执行上下文的概念构建到Liquibase中,这样您就可以标记测试数据更改,并且只在运行单元测试的环境中应用它们。到目前为止,我对结果很满意。当数据库模式与代码期望值之间存在差异,或者当我的SQL中存在错误并且我没有因为数据库重构而丢失任何测试时,测试失败。

    链接是:www.liquibase.org/manual/contexts,但这至少不是我想要的,尽管我可以将我的测试数据公开给一个数据库迁移工具,但我仍然希望它非常接近数据库测试。

    有人想吗?