数据库和单元/集成测试


25

我曾与某人讨论过Web应用程序的单元/集成测试,但我对1个核心思想存在分歧。问题是我正在谈论的人认为,单元测试工作所在的数据库应该在其中预先填充数据,并且我认为在执行测试之前和之后它应该完全为空。

我对数据库中预先填充的数据的担心是,无法确保数据保持良好状态。测试本身将要在数据库中创建,删除和修改数据,因此我真的看不到在开始测试之前在数据库中存储数据是一件好事。

似乎最好的测试数据库功能的方法是进行以下设置:

  1. 在测试实际运行之前的“设置”阶段,您首先要截断数据库中的所有表
  2. 然后,插入将要运行的测试用例所需的所有数据
  3. 然后运行并验证测试用例
  4. 然后在“拆卸”阶段,您再次截断数据库中的所有表

我没有其他更好的方法来确保要测试的数据是可以测试的好数据。

我在这里想念什么吗?这不是测试数据库相关功能的最佳方法吗?始终存在于数据库中的预填充数据库是否有好处(即使在开始测试之前或在测试完成之后)?对想法进行不同解释以更好地阐明我的观点的任何帮助也将是很棒的(也就是说,如果我的观点是有价值的)。


Answers:


21

对我来说,单元测试不应处理数据库,集成测试则应对数据库。

在实践中,处理数据库的集成测试应该有一个带有拆解方法的空数据库,使用基于事务的方法是一个很好的方法(即在安装时创建事务,并在拆解时回滚)。

您的朋友听起来想做的事情是从“回归”的角度进行测试,即在其中拥有真实的数据,并查看系统的反应,毕竟没有一个系统是完美的,并且通常情况下,有一些不良数据会散布在您的域模型的一些怪癖。

您的最佳实践是要走的路,而我倾向于做的是,如果我发现不良数据的情况,编写带有设置的集成测试,然后拆除该确切的情况。


我只是在注意单元测试和集成测试之间的区别,除了我听说单元应该使用模拟数据并且集成应该使用数据库之外(开始了另一个线程程序员。stackexchange.com/ questions / 101300 /… 找出了区别) )。除此之外,您所说的一切似乎都与我的想法保持一致。
ryanzec 2011年

没问题,我为您的其他答案添加了更多信息
Nicholas Mayne

1
为什么不能对数据库进行单元测试?如果将SQL放入存储过程中,则可以使用测试定义的数据对它们进行单元测试,突然之间一切都很容易。这绝对是更多人应该遵循的最佳实践,看看MS
gbjbaanb

1
integration tests- 你什么意思?正如我提到的,使用数据库的模块可以并且应该通过单元测试进行测试。我可以手动嘲笑数据库,也可以替换为内存中实现
hellboy,2015年

6

如果您的测试依赖于数据库,那么我认为更重要的是,您关心的数据处于测试的已知状态,而不是数据库为空。良好测试的一种措施是,每个测试都应出于一个原因而失败,而其他测试都不应出于相同原因而失败。

因此,如果您的测试关心数据的状态,则可以使数据进入该已知状态,然后在运行测试后将数据返回该状态,以使测试具有可重复性。

如果您可以通过模拟使测试与数据状态脱钩,那也将是一件好事。您提到要进行单元/集成测试,但是当然应该将这两件事分开考虑。您的单元测试应尽可能与数据库分离,而集成测试应在数据库处于已知状态下进行测试。


2

好吧,我看到了拥有预先填充的数据库的一个好处:您不必编写代码即可插入所需的数据,因为它已经存在。否则,只有弊端。也许有人修改了数据库上的测试数据?也许有人试图刷新数据?但是最糟糕的是,有一个测试用例严重破坏了数据库……您最终不得不手动重新创建整个数据库几次。

您应该正确编写测试,但我不会截断任何内容:

  • 设置阶段:获得与数据库的连接并插入数据
  • 运行阶段
  • 拆卸阶段:删除插入的数据(截断)

现在,该方案非常适合单元测试。当一个人需要用于单元测试和集成测试的数据时,我发现所有测试用例都通用的一个大设置阶段(我们将所有“插入”重新组合为一种静态方法)也可能很好地工作。这就像您的想法和朋友的想法之间的中间地带。唯一的缺点是,在添加一些新数据时必须非常小心,以免破坏现有的测试用例(但如果像我们一样在每个表中添加两到三行,那应该不是问题)


我是否愿意创建测试所需的数据库部分,而不是有人以导致失败的方式意外修改数据?在测试失败时必须确保数据正确似乎可以避免。
ryanzec 2011年

1
插入对不同测试用例有用的数据的大型设置阶段可能仅对集成测试有用,在集成测试中,您需要检查应用程序的不同部分是否协同工作。拥有这么大的通用“插入”可能是值得的,因为您很可能需要其中一些用于其他集成测试。否则,如果我们只讲纯单元测试,那么我绝对是为每个测试用例插入一组数据。
Jalayn

1

我认为您需要缩小同事的榜样,并弄清楚它们的确切含义。你们可能都在同一页面上。

示例:检查账户交易表

  1. 您是否要针对没有交易的用户/帐户测试查看此表?
  2. 测试添加第一条记录,看看是否可以创建余额。
  3. 当已有记录时创建记录,并检查运行余额和任何其他业务规则。
  4. 查看具有现有记录和所有其他CRUD的表。

是通过执行步骤1和2还是从已经处于此状态的数据库开始(还原备份?)来实现这一点,我不确定这很重要。您将其编写为脚本的想法使我可以更轻松地管理所需的任何更改(例如,如果您忘记创建管理员帐户,而对于新用户则需要它。)。与某些备份文件相比,脚本文件更易于放入源代码管理中。这也受到您是否分发此应用程序的影响。


0

将一些答案的各个方面放在一起,并添加我的2p ...

注意:我的评论特别涉及数据库测试,而不涉及UI测试(尽管显然适用)。

数据库与前端应用程序一样需要测试,但往往会基于“它可以与前端一起工作吗?”进行测试。还是“报告产生正确的结果?”,在我看来,这是在数据库开发过程中进行的很晚的测试,并且不够鲁棒。

除了通常的UAT /性能/等之外,我们还有许多客户在其数据仓库数据库中利用单元/集成/系统测试。测试。他们发现,通过持续的集成和自动化测试,他们在进入传统UAT之前会发现很多问题,从而节省了UAT时间并增加了UAT成功的机会。

我敢肯定,大多数人都会同意对前端或报表测试的数据库测试应采用类似的严格性。

测试的关键是测试小型简单实体,确保它们的正确性,然后再进行复杂的实体组合,在扩展到更广泛的系统之前确保其正确性。

所以给我的答案一些背景...

单元测试

  • 有测试重点来证明单元可以正常工作,例如表,视图,函数,存储过程
  • 应该“存根”接口以删除外部依赖项
  • 将提供自己的数据。您需要一个已知的数据开始状态,因此,如果有可能存在数据进行预测试,则在填充之前应进行截断/删除操作
  • 将理想地在其自己的执行上下文中运行
  • 将自行清除并删除其使用的数据;这仅在不使用存根时才重要。

这样做的好处是,您将删除测试的所有外部依赖关系,并执行最少的测试以证明其正确性。显然,这些测试不能在生产数据库上运行。您可能要进行多种测试,具体取决于单元的类型,包括:

  • 模式检查,有人可能将其称为“数据合同”测试
  • 通过的列值
  • 使用功能,过程,视图,计算列的不同数据值执行逻辑路径
  • 边缘案例测试-NULL,错误数据,负数,值太大

(单元)集成测试

我发现此SE帖子有助于讨论各种类型的测试。

  • 有测试重点来证明单元集成在一起
  • 一起在多个单元上表演
  • 应该“存根”接口以删除外部依赖项
  • 将提供自己的数据,以消除外部数据影响的影响
  • 将理想地在其自己的执行上下文中运行
  • 将自行清除并删除创建的数据;这仅在不使用存根时才重要。

从单元测试转移到这些集成测试时,通常会有更多的数据,以便测试更多的测试用例。显然,这些测试不能在生产数据库上运行。

然后,随着数据量的增加和范围的扩大,这将继续进行系统测试系统集成测试(又名端到端测试)。所有这些测试都应该成为回归测试框架的一部分。用户可能会选择其中一些测试作为UAT的一部分来执行,但是UAT是用户定义的测试,而不是IT定义的测试-这是一个常见问题!

现在,我已经给出了一些背景,可以回答您的实际问题

  • 为单元测试和集成测试预先填充数据可能会导致虚假的测试错误,应避免使用。
  • 确保测试一致的唯一方法是不对源数据进行任何假设并严格控制它。
  • 单独的测试执行上下文很重要,以确保一个测试人员不会与在源代码控制的数据库代码的不同分支上执行相同测试的另一个测试人员发生冲突。

-3

坦率地说,我认为如果在没有数据库的情况下进行单元测试,而数据库的大小与现有生产数据库的大小大致相同,那么将会有很多事情通过测试而导致生产失败。当然,出于这个原因,我也不赞成在一个很小的本地数据库上开发。

如果代码是特定于数据的,那么如何在没有数据的情况下有效地对其进行测试?您将错过查询是否返回正确结果的信息。为什么甚至要考虑针对空数据库进行测试,所有这些告诉您的是语法是否正确,而不是查询是否正确。在我看来,这是短视的。我已经看到太多东西可以运行并通过测试,这是绝对错误的。您是否不想在单元测试中找到它?我做。


我不建议针对空数据库运行,如果您看到第2步,则显示“然后插入要运行的测试用例所需的所有数据”。关于性能问题,我认为这不是单元测试的目的,而是更多的负载测试。对我进行单元测试以进行测试,以确保代码中的逻辑工作正常。如果逻辑上可行,它将对同一基本数据的1条记录或100,000,000,000条记录起作用(这会慢很多)。
ryanzec

数据库查询不仅与逻辑有关,而且您越早发现它对产品的效果越好。对于1条记录有效的方法通常会在prod上超时,而单元测试应该尽快显示出来。
HLGEM 2011年

单元和集成测试仅针对功能而非性能,因此您可以使用少量数据进行测试
user151019 2011年

单元测试永远不要使用数据库-集成测试使用数据库。
尼古拉斯·梅恩

1
您实际上在谈论的是负载测试。如果您有一组验收测试并将其连接到负载测试工具,则可以达到预期的效果。
尼古拉斯·梅恩
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.