【问题标题】:What best practices do you use for testing database queries?您使用哪些最佳实践来测试数据库查询?
【发布时间】:2008-11-03 23:36:19
【问题描述】:

我目前正在测试我们的解决方案,该解决方案具有整个“范围”层:UI、Middle 和无所不在的数据库。

在我加入当前团队之前,查询测试是由测试人员手动制作的查询完成的,理论上这些查询会返回一个结果集,存储过程应该根据各种相关性规则、排序、你有什么来返回。

这会产生副作用,即针对测试人员的查询提交的错误比针对有问题的实际查询更频繁。

我建议实际使用一个已知的结果集,您可以推断它应该如何返回,因为您控制存在的数据 - 以前,数据是从生产中提取、清理,然后填充到我们的测试数据库中。

人们仍然坚持创建自己的查询来测试开发人员创建的内容。我怀疑很多人仍然是。我认为这根本不理想,只会不必要地增加我们的测试足迹。

所以,我很好奇,您使用哪些实践来测试这样的场景,以及在不引入混乱数据的情况下,什么是您可以获得的最佳端到端覆盖率的理想选择?

我遇到的问题是在哪里进行测试的最佳地点。我是否只是直接戳服务,并将该数据集与我可以从存储过程中提取的数据集进行比较?我有一个粗略的想法,并且到目前为止已经足够成功,但是我觉得我们在这里仍然缺少一些重要的东西,所以我正在寻找社区,看看他们是否有任何有价值的见解可能有助于制定我的测试方法更好。

【问题讨论】:

  • 我将继续添加注释,即目标环境实际上都是基于 MS 技术(SQL、IIS、.NET)的,无论好坏。但是,尽管我在这方面缺乏技能,但我仍然很欣赏提到使用诸如 Python 之类的工具的工具。

标签: database tdd integration-testing end-to-end


【解决方案1】:

测试存储过程将要求每个测试人员都有一个单独的数据库实例。这是一个要求。如果您共享环境,您将无法依赖测试结果。它们将一文不值。

您还需要确保在每次测试后将数据库回滚到之前的状态,以使结果可预测且稳定。由于需要在每次测试后回滚状态,这些测试将比标准单元测试花费更长的时间来完成,因此它们可能是您想要运行一整夜的东西。

有一些工具可以帮助您解决这个问题。 DbUnit 就是其中之一,我也相信微软有一个 Visual Studio for Database Professionals 工具,其中包含一些对 DB 测试的支持。

【讨论】:

    【解决方案2】:

    以下是一些指导方针:

    1. 使用独立的数据库进行单元测试(例如,没有其他测试运行或活动)
    2. 始终在同一测试中插入您要查询的所有测试数据
    3. 编写测试以随机创建不同数量的数据,例如插入的随机数在 1 到 10 行之间
    4. 随机化数据,例如对于布尔字段随机插入和真或假
    5. 在变量的测试中保持计数(例如行数、真数)
    6. 对于断言执行查询并与本地测试变量进行比较
    7. 使用 Enterprises Services 事务将数据库回滚到以前的状态

    有关企业服务交易技术,请参阅以下链接:

    http://weblogs.asp.net/rosherove/articles/DbUnitTesting.aspx

    【讨论】:

    • 1-10 行不会进行太多测试。尤其是在 10M-1B 行上的性能。
    【解决方案3】:

    作为持续集成的一部分,我们每晚“构建”数据库查询。这涉及一组数据库调用,这些调用会根据代码中的实际调用以及任何预期的临时查询定期更新。

    这些调用是定时的,以确保:

    1/ 他们不会花太长时间。

    2/ 它们与前一天晚上并没有太大的不同(以一种糟糕的方式)。

    通过这种方式,我们可以快速捕获错误查询或数据库更改。

    【讨论】:

    • 这些“数据库调用套装”,它们是真实调用的克隆吗?如果是这样,您是否将这些与代码中的任何查询一起维护?
    • 我们从代码中提取每个真正的调用并执行一些正则表达式魔术以从中进行静态查询,然后将此静态调用添加到套件中。我们还存储源代码行,以便我们可以检测更改并重做。
    【解决方案4】:

    查询规划器是您的朋友,尤其是在这种情况下。最好的做法是检查索引是否在您期望的时候被使用,并且查询不需要完成额外的工作。即使您的套件中包含压力测试,在您的应用开始停止运行之前捕获昂贵的查询仍然是一个好主意。

    【讨论】:

      【解决方案5】:

      我们为每个开发人员和测试人员预留了一个空白数据库。

      运行测试时 - 每个测试都会清除数据库并加载预期使用的数据。这为我们提供了一个始终已知的状态。

      然后我们可以在同一个数据库上测试几个不同的场景(一个接一个),并且我们永远不会踩到另一个测试人员的脚趾。

      这包括测试数据访问本身。对于服务测试,我们做了很多相同的事情,但我们只测试服务的内部——我们实际上并没有点击服务,而是创建了一个服务处理类的实例并传递了我们需要的一切。这样我们测试的是代码而不是基础设施(消息等)

      【讨论】:

        【解决方案6】:

        Django 提供了数据库单元测试功能。您可以借用他们的设计理念并在其他环境中重现。

        Django 人员提供了 Python 标准 unittest TestCase 类的子类,该类使用已知的固定装置(一组已知的数据行)填充数据库。

        在 Django(和 Python)的情况下,从 JSON 数据提取中填充数据库是最简单的。夹具的其他文件格式可用于其他框架。例如,如果您在 Oracle 中工作,您可能会发现 CSV 文件更易于使用。

        这个TestCase 子类允许编写一个典型的TestCase,使用已知的数据夹具来测试数据库。

        此外,Django 测试运行程序会为测试目的创建一个临时模式。这对 Django 来说很容易,因为它们有一个完整的对象关系管理组件,其中包括 DDL 创建。如果您没有这个可用的,您仍然需要 DDL 脚本,以便您可以创建和处置用于单元测试目的的测试模式。

        【讨论】:

          【解决方案7】:

          SQLServerCentral 有一篇关于名为 tsqlUnit 的 TSQL 单元测试框架的文章 here(您可能需要注册,但它是免费的且没有字符串)。它是开源的,沿袭了 xUnit 框架的传统。

          它遵循 SEAT TDD 模式:

          设置 - 通过操作对象、表格和/或数据来准备测试条件

          练习 - 调用生产代码

          断言 - 检查实际结果是否等于预期结果

          Teardown - 将所有内容恢复到测试开始前的状态。这实际上是通过回滚事务来完成的,这可以使一切保持整洁。

          虽然我没有使用它,但它看起来很有前途,而且我肯定会更详细地研究它。

          框架可以下载here.

          【讨论】:

            【解决方案8】:

            我发现测试发送到数据库的 SQL 而不是查询数据库的结果很有用。

            并不是说我不这样做,但我发现测试它比让数据库过多地提升要快得多。

            【讨论】:

              【解决方案9】:

              这是一个繁重的设置,但我建议使用 TDDing 容器。

              运行您的测试脚本后,构建一个新容器,其中运行您的数据库,使用模拟数据为其播种,然后运行查询并测试返回的内容以及查询是否成功。

              通过这种方式,您可以控制测试环境与生产的接近程度。

              ThoughtWorks

              【讨论】:

                猜你喜欢
                • 2010-11-06
                • 2010-09-25
                • 1970-01-01
                • 1970-01-01
                • 2019-03-18
                • 1970-01-01
                • 1970-01-01
                • 2011-04-11
                • 1970-01-01
                相关资源
                最近更新 更多