【问题标题】:How to make unit tests for DAO classes less brittle in the absence of a static test database?在没有静态测试数据库的情况下,如何使 DAO 类的单元测试不那么脆弱?
【发布时间】:2011-09-21 08:46:22
【问题描述】:

这是扫描仪:

我正在开发一个 DAO 对象,它使用休眠条件 API 来形成许多复杂的查询,以在数据库上执行某些任务(例如跨多个字段的关键字搜索)。

我们需要对此进行单元测试,以确保生成的查询对于各种场景都是正确的。测试它的一种方法(可能更可取)是通过在最后检查它并模拟数据库交互来测试是否正确创建了休眠标准。然而,这是不可取的,因为首先它有点作弊(它只是复制代码会做的事情),而且它也不会检查条件本身是否会导致休眠到 barf 或者当它进入数据库时​​会导致问题。

然后使用的选项是针对测试数据库运行查询。但是,由于历史原因,没有静态测试数据库(例如,代码作为代码的一部分签入的数据库)并且我的项目的职权范围不允许我着手创建一个,我们必须满足于针对使用生产数据定期刷新的共享开发数据库。

当这些刷新发生时,测试背后的数据也可能发生变化,这会使我们的单元测试变得脆弱。我们可以通过在测试中不使用确切的数字来克服它,但这样的测试并不充分。

那么问题来了:在这种情况下人们会怎么做才能让测试变得不那么脆弱?我想到的一个选择是运行一个执行相同查询的本机 SQL(行为上 - 它不必与 hibernate 生成的查询完全相同)以获得预期的数字,然后运行 ​​DAO 版本来查看如果匹配。这样,查询的行为可以始终在初始的原生 SQL 中实现,并且您将始终拥有正确的数字。

对于如何处理这种情况的任何反馈或其他想法,我们将不胜感激。

一个。

更新:

关于 hsqldb/h2/derby 的建议,我很熟悉,但公司还没有准备好走这条路,只在一个测试用例上零碎做是不合适的。

关于我之前的建议,我想详细说明一下 - 考虑一下这种情况:

我想确保我相对复杂的关键字搜索返回 2100 个“John Smith”匹配项。

为了找到预期的数字,我会分析我的数据库并使用 SQL 查询找到数字。将该查询作为测试的一部分,以便您始终知道您正在测试条件的行为有什么缺点?

所以基本上问题是:如果由于某种原因您无法拥有用于测试的静态数据集,您将如何以非脆弱的方式执行集成测试?

【问题讨论】:

    标签: java hibernate unit-testing junit dbunit


    【解决方案1】:

    一种方法是使用内存数据库,如Apache DerbyHSQLDB,并在测试开始前使用DBUnit 预填充数据。

    更新:这是一个很好的article 方法。

    【讨论】:

    • 谢谢 我熟悉 hyperSQL db、dbunit 和 liquibase,过去曾多次使用过它们。但是,在我们正在进行的小项目范围内,这是我目前无权从事的工作。
    • 在午餐时间做,或者提前一个小时来。在你的机器上启动并运行它,然后向你的老板演示,最好是通过一个可以捕捉到最近错误的测试。
    • 设置 hsqldb、创建 hibernate 配置并添加 setUp/tearDown 方法来创建空数据库并指导您的单元测试应该不会花费太长时间。唯一可能需要更长的时间是创建 DBUnit 数据集。但是您可以使用一些真实的数据库从使用 DBUnit 的数据库中提取数据,或者使用一些数据生成器来创建数据。
    • @Andrey Adamovich 不会花很长时间,但这是一个大型遗留项目,我不确定为新方法零敲碎打是最好的方法。但是话又说回来,无论如何我做的其他任何事情都只会用于新代码,所以不妨考虑正确地做。我看看能不能跑起来!
    • @Ashkan:看起来您正试图偿还一些已经产生了相当多利息的技术债务。与 PO 交谈并向她/他提及这一点,该应用程序变得越来越难以运行,并且在测试基础设施上投入一些资金将在短期和长期内获得回报。在短期内,因为无论您生产什么都可能质量更高,并且包含更少的错误。
    【解决方案2】:

    我同意 Andrey 和 Bedwyr 的观点,从长远来看,最好的方法是创建一个专门用于测试的 hsqldb 数据库。如果您没有这样做的选项,那么您的解决方案似乎是一个合适的解决方案。你不能测试所有东西,但你也不想测试任何东西。我已经多次使用这种方法针对集成数据库等测试 Web 服务。但请记住,如果您添加新列等,也必须维护此数据库。

    您必须决定要测试的内容。您不想测试休眠状态,也不想测试数据库是否提供了您所要求的(就 SQL 而言)。在您的测试中,您可以假设 hibernate 可以正常工作,数据库也是如此。

    你说:

    我们需要对此进行单元测试以确保生成的查询是 适用于各种场景。一种测试方法-可能是 更可取-将测试创建的休眠标准 通过在最后检查并模拟数据库来正确地 相互作用。然而,这是不可取的,因为首先它有点 作弊(它只是复制代码会做的事情)和 它也不检查条件本身是否会导致休眠 或者当它进入数据库时​​会导致问题。

    为什么要根据你给它的标准休眠 barf?因为你给了它错误的标准。这不是休眠的问题,而是创建条件的代码。您可以在没有数据库的情况下对其进行测试。

    访问数据库时出现问题?一般来说,Hibernate 会创建适合您给它的标准和数据库方言的 sql,所以同样,任何问题都与标准有关。

    数据库与 hibernate 期望的不匹配?现在您正在测试标准和数据库是否对齐。为此,您需要一个数据库。但是您不再测试标准,而是测试所有内容是否一致,这是一种不同的测试。

    实际上,在我看来,您正在做一个集成测试,从标准到数据库结构的整个链条都有效。这是一个完全有效的测试。

    所以,我所做的是在我的测试中创建另一个到数据库 (jdbc) 的连接以获取信息。我执行 SQL 来获取行数等,或者检查是否发生了插入。

    我认为你的方法是完全有效的。

    【讨论】:

    • 非常感谢。是的,关于在正确级别进行测试,您的观点是绝对正确的,并且我们没有在这里测试 hibernate 或它的标准 API。我试图说明仅测试以某种方式创建标准是徒劳的,正如您所说,我们将需要测试从标准到结构再到数据库的整个链条。这正是我所想的,您的 cmets 对此有很大帮助!干杯。
    【解决方案3】:

    但是,由于历史原因,没有静态测试数据库(例如,将代码作为代码的一部分签入的数据库),并且我的项目权限不允许我着手创建

    您需要做的就是启动 H2 或类似的东西 - 将一些实体放入其中并执行您的集成测试。为几个测试完成此操作后,您应该能够提取一个数据设置实用程序,该实用程序创建一个包含一些测试数据的架构,如果您觉得需要,您可以将其用于所有集成测试。

    【讨论】:

    • 感谢下面的@Andrey Adamovich 我的cmets。您的两个建议都很有道理,但我现在可能无法对这里做事方式的整体结构做出改变。
    猜你喜欢
    • 2010-10-02
    • 2014-10-21
    • 1970-01-01
    • 2023-01-09
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    相关资源
    最近更新 更多