这是scanario:
我正在研究一个DAO对象,该对象使用hibernate条件API来形成一些复杂的查询来执行数据库上的某些任务(例如,跨多个字段的关键字搜索)。
我们需要对此进行单元测试,以确保生成的查询对于各种场景都是正确的。测试它的一种方法 - 可能更好 - 将通过最后检查并模拟数据库交互来测试hibernate标准是否正确创建。然而,这是不可取的,因为它首先是有点作弊(它只是复制了代码将要做的事情),而且它也不会检查标准本身是否会导致hibnate进入barf,或者当它进入数据库时会导致问题。
然后,使用的选项将针对测试数据库运行查询。但是,由于历史原因,没有静态测试数据库(例如,代码作为代码的一部分签入的代码),并且我的项目的职权范围不允许我开始创建一个,我们必须满足于对使用生产数据定期刷新的共享开发数据库。
当这些刷新发生时,测试背后的数据也会发生变化,这将使我们的单元测试变得脆弱。我们可以通过在测试中不使用确切的数字来克服它,但它并不是那么充分的测试。
那么问题是:人们在这样的情况下做些什么来使测试变得不那么脆弱?我想到的一个选项是运行一个执行相同查询的本机SQL(行为 - 它不必与hibernate生成的查询完全相同)来获取预期的数字,然后运行DAO版本以查看如果它匹配。这样,查询的行为总是可以在初始本机SQL中实现,并且您将始终拥有正确的数字。
非常感谢有关如何管理这种情况的这方面或其他想法的任何反馈。
一个。
更新
关于hsqldb / h2 / derby的建议,我对它们很熟悉,但该公司还没有准备好沿着那条路走下去,只在一个测试用例上做零碎的做法是不合适的。
关于我之前的建议,我想详细说明一下 - 考虑这种情况:
我想确保我的相对复杂的关键字搜索为“John Smith”返回2100匹配。
为了找到预期的数字,我会分析我的数据库并使用SQL查询找出数字。将该查询作为测试的一部分有什么缺点,以便您始终知道您正在测试标准的行为?
所以基本上问题是:如果由于某种原因你没有静态数据集进行测试,你将如何以非脆弱的方式执行集成测试?
答案 0 :(得分:6)
一种方法可能是使用内存数据库,如Apache Derby或HSQLDB,并在测试开始前使用DBUnit预先填充数据。
更新:这是一个关于aproach的好article。
答案 1 :(得分:5)
我同意Andrey和Bedwyr的观点,从长远来看,最好的方法是创建一个专门用于测试的hsqldb数据库。如果您没有选择这样做,那么您的解决方案似乎是合适的。你不能测试一切,但你也不想测试任何东西。我已经使用这种方法几次来测试针对集成数据库等的Web服务。但是请记住,如果添加新列等,也必须维护此数据库。
你必须决定你要测试的是什么。你不想测试hibernate,你不想测试数据库是否提供你所要求的(就SQL而言)。在测试中,您可以假设hibernate和数据库一样有效。
你说:
我们需要对此进行单元测试以确保生成的查询 适用于各种场景。测试它的一种方法 - 可能是 首选 - 将测试创建的休眠标准 通过最后检查并模拟数据库来正确地进行操作 相互作用。然而,这是不可取的,因为它首先是有点 作弊(它只是复制代码将要做的事情)和 它也不会检查标准本身是否会导致休眠到barf 或者当它进入数据库时会导致问题。
为什么要按照你给出的标准来休眠barf?因为你给它错误的标准。这不是hibernate的问题,而是使用创建条件的代码。你可以在没有数据库的情况下测试它。
它到达数据库时有问题吗?通常,Hibernate会创建适合您提供的标准和数据库方言的sql,因此,任何问题都与条件有关。
数据库与hibernate所期望的不匹配?现在,您正在测试条件和数据库是否一致。为此,您需要一个数据库。但是你不再测试标准,你正在测试一切都是一致的,一种不同的测试。
实际上,在我看来,你正在进行集成测试,从标准到数据库结构的整个链条都有效。这是一个非常有效的测试。
所以,我所做的是在我的测试中创建另一个与数据库(jdbc)的连接以获取信息。我执行SQL以获取行数等,或检查是否发生了插入。
我认为你的方法非常有效。
答案 2 :(得分:3)
但是,由于历史原因,没有静态测试数据库(例如,代码作为代码的一部分签入的代码),我的项目的职权范围不允许我开始创建
您需要做的只是启动H2或类似 - 在其中放置一些实体并执行集成测试。完成一些测试之后,您应该能够提取一个数据设置实用程序,该实用程序创建一个包含一些测试数据的模式,如果您认为有需要,可以将其用于所有集成测试。