代码之家  ›  专栏  ›  技术社区  ›  DMCS

不接触实际数据库的MSTest单元测试和数据库访问

  •  6
  • DMCS  · 技术社区  · 15 年前

    在代码中,我与数据库(不是解决方案文件的一部分)交互。数据库由一个独立的DBA团队拥有,我们开发人员编写的代码只允许访问存储过程。但是,我们可以全面查看数据库的进程、表和列(它的定义)。对于依赖于数据的代码,我目前编写了在表中屏蔽数据的单元测试(并在单元测试完成后删除这些行),这样我就可以运行单元测试来运行与DB交互的代码。要执行此操作的所有代码都在测试文件中(尤其是在ClassInitialize()和ClassCleanup()函数中)。然而,我的新同事给了我一些悲伤,他们称我的单元测试风格为“破坏性的”,因为我读/写dev数据库插入和删除行。在我们编写单元测试代码时,数据库设计通常不稳定,因此在我们将QA部门的精力投入到我们的程序之前,我们可以在存储的过程代码中发现问题(节省资源)。它们都告诉我在运行MSTest单元测试时有一种方法可以克隆到数据库内存中,但是它们不知道如何克隆。我在网上做过调查,找不到一种方法去做我的同事需要我做的事情。

    有人能肯定地告诉我,在我上面展示的环境中,是否会发生这种情况?如果是的话,你能给我指出正确的方向吗?

    6 回复  |  直到 8 年前
        1
  •  7
  •   GarethOwen    14 年前

    是否有可用于创建数据库的SQL脚本?您应该有,它们应该在版本控制之下。如果是,则可以执行以下操作:

    在你 测试设置代码 :

    • 使用SQL脚本创建“临时”数据库。使用唯一的名称,例如unittestdatabase_[timestamp]。
    • 在测试数据库中设置测试所需的数据。理想情况下,使用公共API函数(如createuser、addnewcustomer),但如果所需的API不存在,则使用SQL命令。使用API设置测试数据可以使测试对低级实现(即数据库模式)的更改更加健壮。这就是我们编写单元测试的原因之一,以确保对实现的更改不会破坏功能。
    • 运行单元测试,使用依赖项注入将测试数据库连接字符串从测试代码传递到测试代码中。

    在你 测试拆卸代码 ,删除数据库。理想情况下应该使用数据库卸载脚本来完成,该脚本也应该在版本控制下。

    通过在[assemblyinitialize]、[classinitialize]或[testinitize]方法中创建数据库,可以控制创建单元测试数据库的频率:例如每个测试项目、测试类或测试方法,或组合。

    这是我们成功使用的一种技术。这个 优势 是:

    • 每次运行单元测试时,我们都在测试数据库安装脚本是否与代码一起工作。
    • 测试隔离,即测试只影响其测试数据库。如果回滚代码出错也没关系,您不会接触到任何其他人的数据。
    • 对准则的信心。也就是说,因为我们使用的是一个真正的数据库,所以单元测试给了我更多的信心,即代码可以工作,而不是我模仿数据库。当然,这取决于您的高级集成/组件测试套件有多好。

    缺点 :

    • 单元测试依赖于外部系统(DBMS)。您需要在测试设置代码中找到DBMS的名称。这可以通过使用配置文件或查看正在运行的本地DBMS的运行时来完成。
    • 数据库安装脚本可能会减慢测试速度。根据我们的经验,测试仍然运行得足够快,并且有很多机会进行优化。我们在大约1分钟内运行了大约400个单元测试的测试套件,其中包括在本地安装的SQLServer2008上创建5个独立的数据库。
        2
  •  4
  •   Ben Cawley    15 年前

    如果您可以在业务逻辑代码和数据访问层之间创建一个“接缝”,那么您应该可以。使用接口来表示DAL向业务逻辑公开的合同,然后编写自己的一组假对象或使用模拟工具(如Rhino Mocks)。

    如果您正在编写命中该数据库的测试,那么您将面临巨大的维护难题,因为当您声明时,该数据库正在更改,而且很难维护可以访问该数据库的环境。您实际编写的是集成测试,它仍然有效,但真正的单元测试不应该依赖于数据库、文件系统等。

        3
  •  1
  •   Jackson Pope    15 年前

    我将模拟出数据库,而不是尝试与测试实例交互。这将使您的测试更快(因此您更有可能运行它们)。

        4
  •  1
  •   Richard Banks    14 年前

    假设您不能按照其他人的建议进行操作,因为您实际上是在测试存储过程,按照您的期望进行操作,那么我认为您的同事所指的是使用内存中的数据库。

    当人们谈论内存中的数据库进行测试时,他们通常指的是sqlite。他们在测试开始时在内存中建立数据库,并在测试结束时将其销毁。不幸的是,sqlite不支持存储过程,所以这对您没有帮助。

    我建议您为存储过程编写特定的集成测试,并像当前那样插入/删除数据。注意,如果您将测试包装在一个事务中,然后回滚,这会更容易。如果您有可用的存储过程,也可以使用Visual Studio中的数据库“单元测试”功能来测试存储过程。

    对于其余的代码,按照@ben的建议模拟DAL,并将业务逻辑测试为正常的单元测试。但是,考虑到DAL是一个静态类的复杂性,您需要做一些工作来包装DAL,并开始在整个应用程序中使用包装类——有点像ASP.NET MVC如何处理httpContext。

        5
  •  1
  •   DMCS    14 年前

    即使有了赏金,我也不知道这是否存在。我想在这一点上,那些告诉我这项技术确实存在的人可能是错的。

        6
  •  0
  •   Pushpendra    8 年前

    我们不能要求DBA提供数据库的备份,并在您的本地计算机上还原它,然后对它进行测试吗? 备份和恢复是我认为最快的方法。