存储过程的单元测试

dez*_*zso 44 best-practices unit-test

我已经考虑这个问题很久了。

基本问题是:如何对存储过程进行单元测试?

我发现我可以相对轻松地为经典意义上的函数设置单元测试(我的意思是它们获得零个或多个参数并返回一个值)。但是,如果我考虑一个看似简单的过程在某处插入一行的真实示例,在插入之前或之后有几个触发器执行此操作,甚至定义“单元”的边界也非常困难。我应该只测试INSERT本身吗?我认为这相当简单——价值相对较低。我应该测试整个事件链的结果吗?除了这是否是单元测试的问题外,设计一个合适的测试可能是一项非常艰巨的工作,在此过程中会出现许多额外的问号。

然后是不断变化的数据的问题。在UPDATE影响的不仅仅是几行的情况下,每个可能受影响的行都必须以某种方式包含在测试用例中。DELETEs 等等的进一步困难。

那么如何对存储过程进行单元测试呢?复杂性中是否存在一个完全没有希望的门槛?维护需要哪些资源?

编辑还有一个小问题,基于 AlexKuznetsov 的回答:或者是否存在一个完全无用的阈值?

A-K*_*A-K 32

我们已经这样做了将近五年,我们认为明确测试修改绝对是可行的,但速度很慢。此外,除非我们使用单独的数据库,否则我们无法轻松地从多个连接同时运行此类测试。相反,我们应该隐式地测试修改——我们使用它们来构建至少一些测试数据,并验证我们的选择返回预期结果。

我写了一篇题为“关闭那些漏洞:从单元测试 T-SQL 中学到的教训”的文章,以及一些博客文章

关于您的问题“复杂性是否存在一个完全没有希望的门槛?”,复杂的模块比简单的模块更需要测试。

为了简化维护,我们生成预期结果,并将它们存储在单独的文件中 - 这会产生巨大的差异。


Lei*_*fel 15

是的,您应该将整个事件链作为一个单元进行测试。因此,在您的示例中,有一个插入表并导致多个触发器触发的过程,您应该编写单元测试来评估各种输入的过程。每个单元测试应该通过还是失败取决于它是否返回正确的值、正确更改表的状态、创建正确的电子邮件,甚至发送正确的网络数据包(如果它被设计为做这样的事情)。简而言之,应该验证该单元的每一个效果。

你是对的,设计单元测试需要一些工作,但大部分工作必须手动测试单元,你只是保存测试单元所需的工作,以便将来在进行更改时进行测试可以同样彻底且容易得多。

更改数据确实使测试变得更加困难,但它不会使测试变得不那么重要,并且实际上增加了单元测试的价值,因为大多数困难只需要考虑一次,而不是每次对单元进行更改时。保存的数据集、作为设置/拆卸一部分的插入/更新/删除以及范围狭窄的操作都可以用来使这更容易。由于问题不是特定于数据库的,因此细节会有所不同。

高端或低端没有复杂性阈值可以阻止您进行测试或单元测试。考虑以下问题:

  1. 你总是编写无错误的代码吗?
  2. 小单位总是没有错误吗?
  3. 大单位有BUG可以吗?
  4. 造成灾难需要多少个错误?

假设您开始一项新工作,并负责对在许多地方使用的一个小函数进行优化。整个应用程序是由一名甚至都不记得的员工编写和维护的。这些单位有描述正常预期行为的文档,但其他的很少。您更愿意找到其中的哪一个?

  • 应用程序中的任何地方都没有单元测试。进行更改后,您可以对单元本身进行一些手动测试,以确保它仍然返回文档中的预期值。然后,您可以将其推出到生产环境中,交叉手指并希望它可以工作(毕竟,您总是编写无错误的代码并且一个单元中的优化永远不会影响另一个单元)或花费大量时间学习整个应用程序如何有效,因此您可以手动测试直接或间接影响的每个单元。
  • 整个应用程序中的单元测试每天或按需自动运行。他们不仅检查正常输入值及其预期响应,还检查异常值和引发的预期异常。您进行更改并立即运行应用程序的单元测试套件,发现其他三个单元不再返回预期结果。其中两个是良性的,所以你调整单元测试来解决这个问题。第三个需要另一个轻微的调整和一个小的新单元测试。进行更改后,整个测试套件都会成功,您可以放心地进行更改。


Fra*_*ens 8

对于 PostgreSQL,请查看pgTAP

pgTAP 是一套数据库函数,可以轻松地在 psql 脚本或 xUnit 样式的测试函数中编写 TAP 发射单元测试。


小智 6

如果您希望完全在 SQL 上完成对存储过程的测试,请查看http://tsqlt.org/

它与 MS SQL 2005 SP2 及更高版本兼容,优点是开发人员不需要知道 C# 或其他语言来实现测试。

还有一些工具可以做模拟表和视图,以帮助您实现可重新运行的测试套件。