Unit testing 对使用数据库的代码进行单元测试

Unit testing 对使用数据库的代码进行单元测试,unit-testing,Unit Testing,我很想知道人们在开发自动单元测试时采用了什么方法来测试数据库 在运行测试套件之前,您是否安装了QA数据库(已知起点) 或 您是否构建了数据库存根,以便在数据库调用发生时随时备用 编辑:相关的问题,但不是重复的,尽管对手头的事情很重要:我们做了一些技巧: 编辑:我们每个用户都有单独的数据库。我们的buildserver也有自己的数据库。额外硬盘的成本远低于开发人员影响彼此测试的成本 我们的应用程序可以生成表并自行执行升级步骤(没有单独的db脚本)。这对我们的客户很有帮助,因为他只需要提交一份战争文

我很想知道人们在开发自动单元测试时采用了什么方法来测试数据库

在运行测试套件之前,您是否安装了QA数据库(已知起点)

您是否构建了数据库存根,以便在数据库调用发生时随时备用

编辑:相关的问题,但不是重复的,尽管对手头的事情很重要:

我们做了一些技巧:

编辑:我们每个用户都有单独的数据库。我们的buildserver也有自己的数据库。额外硬盘的成本远低于开发人员影响彼此测试的成本

  • 我们的应用程序可以生成表并自行执行升级步骤(没有单独的db脚本)。这对我们的客户很有帮助,因为他只需要提交一份战争文件,他就完成了。在启动Spring上下文的其余部分之前,应用程序查看数据库并执行所需的任何DDL语句
  • 我们的测试套件有一些代码,可以卸载Spring上下文,删除数据库,并使用干净的数据库重新启动上下文。如果愿意,我们可以选择关闭此选项
  • 我们所有的数据库/SQL单元测试都是Spring事务集成测试。这意味着测试完成后,事务将回滚,其他unittests将再次查看干净的数据库
  • 除此之外,我们尝试尽可能多地进行模拟测试,因为单元测试实际上并不打算成为集成测试。因此,尝试将servicelayer与DAO层分离。这还可以帮助您更容易地发现问题,因为您隔离了所有问题


    在某种程度上,我确实认为您需要访问数据库,因为它不是我们所生活的理想/学术世界:-)

    取决于具体情况,但在传统系统上,我不想删除数据库,我经常引入一个接口,比如说IfoodManager,它具有返回ADO.Net实体的方法,如数据表或数据集。当然,它不必是一个接口,但它可以是一个虚拟方法。然后,在我的测试中,我使用一个小API,它有一个我很久以前自己构建的流畅的接口,我使用它来创建数据集和表,并用测试值填充它们,这样我就可以从我的赝品中返回它们

    fluent界面的外观如下所示:

    return DataTableBuilder.Create()
        .DefineColumns("a, b")
        .AddRow().SetValue("a", 1).SetValue("b", 2).DoneWithRow()
        .AddRow().SetValue("a", 10).SetValue("b", 20).DoneWithRow()
    .Table
    
    正如我所说的,这只是我使用的方法之一,主要用于遗留系统,我不想在这些系统中引入对框架等的新依赖。然而,这是一种我没有见过很多其他人使用的技术,所以我认为值得一提

    编辑: 我忘了澄清这是为了删除数据库,所以在本例中没有测试与数据库的交互。实际的交互将在IFooDBManager的具体实现中进行,以测试是否完全需要其他东西


    当然,并不是所有这样的接口上的方法都会返回东西,还有一些写入数据库的方法,我通常在Rhinomock中通过交互测试来测试这些方法,我对这些方法设定了期望值。

    我们正朝着使用模拟框架的方向发展——它们模拟数据库之类的资源,使用这些框架是有效运行单元测试的一种实用方法

    我们正在研究的框架之一是Rhino Mocks。你可以在下面的链接中阅读。它还很好地介绍了为什么需要这样的框架

    驻留的“数据库存根”通常被称为“假存储库”或“模拟存储库”。这是个好主意。您可以手工编写它们(对于简单的情况来说并不难),或者使用Rhino Mocks之类的框架来生成它们。你没有提到你在用什么语言工作。Rhino mocks是针对.Net的

    如果使用模拟存储库,则可以对处理数据的代码运行测试,而无需实际使用数据数据库。这使得测试运行得非常快,这是一件好事

    当然,您仍然需要在某个阶段测试真正的存储库,这是一个更大的问题。这些测试运行得较慢,因为它们使用的是真实的数据库。由于速度和依赖性问题,有些人会将其归类为“集成测试”,而不是单元测试

    我不介意你怎么称呼他们,但是把这些测试分开是个好主意


    数据一致性的一个好主意是在测试之前开始一个db事务,然后回滚。这样,数据库状态将恢复到测试前的状态。

    如果您使用的是NHibernate,您可以非常容易地恢复,这非常快。

    实际上,您应该同时执行这两项操作。当您说“构建数据库存根”时,这暗示着在单元测试中进行模拟。当您谈到“安装一个QA数据库(已知的起点)”时,这暗示了您实际访问数据库的集成测试。单元测试在游戏中出现得更早,是模拟的开始。模拟比实际命中数据库快得多。因此,当您运行许多单元测试时,模拟将节省大量时间。Rhino Mocks是我个人使用过的一个很棒的框架。但是有几种模拟框架,请找到最适合您的框架


    在某个时候,您应该对整个数据库进行集成测试,我发现最好的方法是使用一个脚本来完全创建数据库,并使用一组已知的数据填充数据库。然后确保除了集成测试之外,没有任何东西会接触到新创建的数据库,然后进行测试。

    在我的数据库测试实践中,我使用了NUnit,在执行整个测试序列之前,数据库已安装并填充了测试数据。
    当然,这个过程并不是很快,但在测试运行时,是什么阻止了您进行其他工作。

    我通常使用两种方法

    依赖于数据库的代码