原子测试在动态创建的环境中有意义吗?

时间:2013-02-19 14:39:22

标签: unit-testing integration-testing jasmine

我们正在构建一个产品,允许用户在这些数据库(WebApp)中创建自定义数据库和存储数据。

我们测试前端(coffeescript)的问题是每个测试都应该是原子的,但这需要设置一个数据库,以查看该数据库中的项目是否可以创建并持续存在或查看数据库中的更改如何影响项目

基本上,问题是进入项目测试所需的设置代码基本上设置了一个新的数据库,因此等于测试设置新数据库的代码。

有两种方法可供使用:

1)使用每组测试创建和拆除新数据库

  • (+)Sorta Atomic(如果设置数据库失败,仍会失败)
  • ( - )需要花费大量时间执行
  • ( - )大量的代码
  • ( - )无法探索创建的环境
  • ( - )凌乱的错误,一切都失败

2)逐步进行设置,作为彼此依赖的单独测试,在测试开始时进行清理程序

  • (+)可以通过UI访问创建的环境(不会自动拆除)
  • (+)逐步测试,减少整体/重复代码
  • ( - )测试依赖于彼此(凌乱)
  • ( - )有些整体凌乱

我们想知道,在这样一个动态的环境中,测试应该是原子的黄金法则是否有意义?

2 个答案:

答案 0 :(得分:2)

如果您正在与数据库交谈,那么您不会进行原子测试。

您需要mock数据库界面并转而与模拟对话。这将是快速的,你将能够使用模拟引入使用真实数据库很难的错误。

答案 1 :(得分:2)

基本上,你所说的是集成测试。这些与单元测试不同。集成测试的示例是自动UI测试或编码UI测试。在我工作过的大多数项目中,我们都进行过两种类型的测试,我强烈建议您在项目中同时使用这两种类型。

这两项测试背后的理念略有不同。

  • 单元测试旨在测试功能的孤立位。
  • 他们意味着非常快。
  • 开发人员应该能够在合理的时间内在他们的机器上运行它们。

这种哲学有各种后果。

  • 因为单元测试正在测试一些孤立的功能,所以你应该使用模拟和存根来隔离环境的其余部分,而只关注一小部分功能。
  • 隔离有助于您在编写这些测试时"设计思维" 。实际上,这就是为什么单元测试需要快速的原因,因为开发人员在设计和重新设计过程中积极且不断地更改代码和单元测试。设置,更改和运行单元测试的开销应该非常低。我应该能够忽略除了我试图解决的问题之外的一切,并快速迭代并重申我的设计和测试。这是TDD背后的想法,它声称可以帮助编写好的可测试代码。如果您花费很长时间尝试设置过于复杂的单元测试,那么您必须重新考虑您的设计。
  • 快速性意味着您可以将其作为持续集成构建的一部分运行。
  • 缺点是因为您正在单独测试每个功能,所以您不知道它们是否将作为一个整体协同工作。每次你编写一个模拟器时,你都隐含地假设系统的其余部分是如何工作的,并且系统的其余部分当前正在工作(即,在部署或运行​​时没有其他任何部分被破坏)或修补OS等。)

集成测试旨在从端到端测试功能。您尽量不要模拟或隔离系统的任何部分。

这种哲学还有各种后果。请注意,集成测试不需要快速。

  • 集成测试本质上需要在完全部署之后运行(而不是单元测试,可以在代码编译后立即运行)。
  • 因为它们需要更长时间,所以您不能将它们作为CI环境的一部分运行,但您仍需要定期运行它们。我们通常将它们作为我们夜间构建的一部分来运行。或者你可以每天运行两次等。
  • 因为集成测试采用黑盒方法处理整个系统,所以它并没有真正帮助你"设计思维" 关于如何实际构建系统。但它确实有助于您思考整个系统的规范。即 系统应该做什么,而不是 它应该做什么。

请注意,在这两种情况下,测试原则仍然适用。每项测试都与其他测试不同。这样,当测试失败时,您可以确定导致其失败的所有条件,并专注于仅修复它。只是集成测试会触及尽可能多的系统部件。

为您举例说明我们当前的项目。

让我们说我们需要编写一些功能,要求我们向数据库添加一个新表,并将其引入所有层以在UI中显示它。

我们首先创建业务逻辑类,域类,编写适当的Web服务,构建视图模型,修改数据库等。在执行这些操作时,我们编写单元测试来测试我们当前编写的代码。因此,在构建业务逻辑类时,我们会模拟其他所有内容,以确保类中的逻辑有效(例如,60岁以上的客户可以获得50%的汽车保险折扣等。)

一旦我们这样做,我们现在需要更新我们的部署脚本/包等以便能够部署它。即更新数据库创建SQL脚本和数据库更改SQL脚本等(在您的情况下,这将是复杂的过程)。

现在我们编写集成测试。在这种情况下,我们可以测试从SQL Server到Web服务。有一个SQL Integration测试基类,它包含每个测试的设置和拆除方法。在设置中,我们使用sql部署脚本创建一个全新的数据库。每个测试还指定一个测试数据sql脚本。因此,例如,此测试数据脚本可能会将新记录插入到年龄为70年的客户端表中。我们将此脚本作为" Arrange"的一部分运行。我们的考试。然后进行Web服务调用以搜索60岁以上的客户。这是" Act"测试的一部分,从结果中,我们检查以确保我们只返回我们已插入数据库的用户。在测试结束时,数据库将被删除。当SQL数据库中的列不可空或日期时间列溢出时,我们已经发现了错误,因为.Net中的默认最小日期时间与SQL服务器的最小日期时间不同。

某些功能要求我们与Oracle数据库进行交互。例如,如果将新记录添加到Oracle,则触发器/数据库过程启动并将该记录传输到SQL,然后我们需要将其启动到层。在这种情况下,我们有一个OracleSQL集成测试基类。正如您可能已经猜到的那样,这遵循一个简单的模式,但是创建了Oracle和SQL dbs,将测试数据插入到Oracle中,并在测试结束时将它们两个都吹掉。

开发人员通常选择Web服务层来编写集成测试。另一方面,测试人员使用UI自动化工具来确保数据实际显示在屏幕上。例如,他们将记录一个进入网页的测试,点击搜索按钮,放置" 60"进入年龄框,单击搜索按钮等。该测试可能会利用相同的测试数据sql脚本插入开发人员编写的测试数据(或者测试团队可能会来开发人员并请求帮助制作sql脚本以插入任何高度错综复杂的内容他们能想到的数据)。但重点是,一旦创建了测试数据插入脚本,它就会利用相同的底层系统来吹走整个数据库,创建一个新数据库,插入测试数据,并运行指定的测试。

因此,要回答您的问题,您将需要两种类型的测试,单元测试和集成测试。您可能需要投入一些初始工作来创建一些基类或辅助方法来创建/删除数据库,自动部署以安装/卸载系统的其他组件等。无论如何,您必须为最终部署执行此操作。集成测试还将与您的部署策略密切相关并依赖于您的部署策略。在我看来,这是一个优势,而不是一个缺点。虽然最初设置它可能会很痛苦,但集成测试隐式测试的一个问题是您的部署机制。如果在部署/安装系统所需的任何组件时出现任何问题,您希望尽快了解它。不是在您应该部署到生产的前一天。

一套好的测试是非常宝贵的。它还需要孤立,严谨和全面。测试不应该在他们不需要时失败,但更重要的是,他们应该在需要时失败。当它们失败时,您希望它们提供尽可能多的信息并指出您失败的确切位置。这使得修复问题变得更加容易。无论何时,只要您投入构建​​此测试套件,就可以立即收回成本。