如何为依赖动态数据的函数编写单元测试?

时间:2012-04-23 20:50:24

标签: database unit-testing dynamic-data

假设您有一个网站,它使用一个函数从数据库中检索数据并返回要显示/解析的结果/等...

由于从数据库中检索的数据是动态的,并且可能每天都会发生变化,因此如何为此功能正确编写单元测试?

假设该函数应该返回一组结果。显然,单元测试可以测试是否返回数组。但是,由于MySQL查询编写错误,当数组本身的内容不正确时会发生什么?数组的大小可能为零,或者数组的内容可能不正确。由于它依赖于不断变化的数据,单元测试如何知道什么是正确的,什么不是?是否需要从单元测试本身调用数据库,以便有一些东西可以与它进行比较?

如何为依赖动态数据的函数正确编写单元测试?

6 个答案:

答案 0 :(得分:7)

单元测试,以理想的形式,应该只测试一件事。在这种情况下,您正在测试两件事:

  1. 你的功能逻辑
  2. 数据库检索
  3. 所以我建议使用以下重构:

    1. 将数据库检索逻辑移动到单独的函数
    2. 让您要测试的功能调用其他功能
    3. 模拟出返回数据的函数,这样您就可以单独测试应用程序的逻辑
    4. 如果它有意义(如果你只是依靠另一个库来做这个,那么希望lib已经有了测试),为动态检索功能写一个单元测试,你不能测试细节,但是可以测试返回数据的结构和合理性(例如,它设置了所有字段,现在是5秒内的时间)。
    5. 此外,通常最好在测试环境中运行单元测试,在该测试环境中您可以完全控制存储在数据库中的内容。您不希望针对生产数据运行这些数据。

答案 1 :(得分:1)

如果你的函数除了从数据库中提取数据之外还做了一些有趣的事情,你应该将检索提取到一个不同的函数中并模拟它,这样你就可以测试其余的了。

这仍然让您完成测试数据库访问的任务。你不能真的对它进行单元测试,因为根据定义,它不会访问任何数据库,你可以测试它是否发送你认为应该的sql语句,但是如果sql语句实际上有效则不行。

所以你需要一个数据库

您有多种选择:

1)为这些测试创建一个固定的数据库,测试不会改变它。

亲:从概念上讲很容易 骗局:难以维持。测试变得相互依赖,因为它们依赖于相同的数据。无法测试更新,插入或删除的内容(更不用说DDL)

2)在测试期间创建数据库。现在你有两个问题:为测试设置数据库并用数据填充它。

设置:

1)运行一个数据库服务器,为需要运行测试的每个人提供一个用户/模式/数据库(至少是devs + ci-server)。可以使用诸如hibernate之类的东西或用于部署的脚本来创建模式。

效果很好,但让老式的DBA疯狂。应用程序不得依赖于架构名称。当您拥有应用程序使用的多个架构时,您也会遇到问题。此设置相当慢。它可以帮助投入快速光盘。像RAM光盘一样

2)拥有一个内存数据库。易于从代码开始和快速。但在大多数情况下,它的行为与生产数据库相同。如果你使用试图隐藏差异的东西,这就不那么重要了。我经常在第一个构建阶段使用内存数据库,在第二阶段使用真实内容。

加载testdata

1)人们告诉我使用dbunit。我不相信它似乎是大量的XML,并且在列或约束发生变化时难以维护。

2)我更喜欢普通的应用程序代码。 (在我的情况下,Java + Hibernate),但是在生产中将数据写入数据库的代码在很多情况下应该适合为测试编写测试数据。它有一个特殊的API,可以隐藏满足所有外键和内容的细节:http://blog.schauderhaft.de/2011/03/13/testing-databases-with-junit-and-hibernate-part-1-one-to-rule-them/

答案 2 :(得分:0)

你不能,真的。您需要一个有保证的静态数据集来创建可靠的单元测试。也许数据库快照对您有用。

动态数据在其他方面非常有用,例如执行回归测试......

答案 3 :(得分:0)

大多数测试都关注于获取数据等内容所涉及的逻辑路径。不是数据本身的有效性。数据的有效性仅在您的应用程序以某种方式计算或汇总它或其他任何内容时才有意义,在这种情况下,您应该能够控制输入并验证结果是否正确。

也就是说,有时您确实想要使用您的应用用于验证退货的同一数据库。例如,如果您正在测试一个返回过滤数据集的函数,那么您的单元测试可以执行相同的查询,然后对每个记录主键进行逐行比较,并验证您的函数是否返回你期待的同一组数据。

我不知道这是否是您的具体问题,但是在单元测试中命中数据库执行断言没有任何问题。至少我一直这样做,没有人试图让我被捕:)

答案 4 :(得分:0)

忽略你正在谈论数据库的事实我认为你可能正在寻找你的单元测试来涵盖每一个可能导致收益递减的事件。如果我是你,我将覆盖标准路径,然后是几个边缘情况。事实上,你无法务实地测试一切。

这是一些进一步的阅读

http://37signals.com/svn/posts/3159-testing-like-the-tsa
How deep are your unit tests?
http://johnnosnose.blogspot.co.uk/2012/04/re-over-testing.html
http://martinfowler.com/bliki/TestCoverage.html

查看与特定数据库相关的问题,要测试此功能,您可能需要创建一个seam来预先填充数据,以便涵盖这些情况。

答案 5 :(得分:0)

我会在测试中构建数据。这样,您甚至可以测试不断变化的数据的复杂场景。关键是您可以通过使用专用测试数据库

来控制测试中的数据更改

步骤1:将您需要的数据插入仅供测试使用的数据库中 第2步:db现在处于稳定的可预测状态,因此您可以运行查询并测试输出