MSTest单元测试和数据库访问,无需触及实际数据库

时间:2010-11-15 17:09:04

标签: database unit-testing mstest clone

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

有人可以告诉我这是否可能发生在我上面显示的环境中?如果是这样,你能指出我正确的方向吗?

6 个答案:

答案 0 :(得分:7)

您是否有可用于创建数据库的SQL脚本?你应该有,他们应该受版本控制。如果是,那么您可以执行以下操作:

测试设置代码

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

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

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

这是我们使用的一项非常成功的技术。 优势是:

  • 每次我们运行单元测试时,我们都会测试我们的数据库安装脚本是否与代码一起工作。
  • 测试隔离,即测试只影响他们的测试数据库。如果回滚代码出错并不重要,那么你就不会触及任何其他人的数据。
  • 对代码的信心。也就是说,因为我们使用的是真正的数据库,所以单元测试让我更有信心代码工作比我模拟数据库更有信心。当然,这取决于您的高级集成/组件测试套件有多好。

<强>缺点

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

答案 1 :(得分:4)

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

如果您正在编写那些命中该数据库的测试,那么您将面临巨大的维护问题,因为正如您所述,数据库正在发生变化,同时也难以维护可访问数据库的环境。您实际编写的是集成测试,它仍然有效,但真正的单元测试不应该依赖于数据库,文件系统等。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

假设您无法做其他人建议的事情,因为您实际上正在测试存储过程,请执行您期望的操作,然后我认为您的同事所指的是使用内存数据库。

当人们谈论用于测试的内存数据库时,他们通常指的是SQLite。它们在测试开始时在内存中构建数据库并在最后销毁它。不幸的是,SQLite不支持存储过程,因此对您没有帮助。

我建议您为存储过程编写特定的集成测试,并按照目前的方式插入/删除数据。请注意,如果将测试包装在随后回滚的事务中,则会更容易。您还可以使用Visual Studio中的数据库“单元测试”功能来测试sprocs(如果有的话)。

对于其余的代码,请将您的DAL模拟为@Ben建议并将您的业务逻辑测试为正常的单元测试。但是,鉴于您的DAL是一个静态类的复杂性,您将不得不做一些工作来包装DAL并开始在整个应用程序中使用包装类 - 有点像ASP.NET MVC处理HttpContext。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

我们是否可以要求DBA提供数据库备份并将其还原到本地计算机上并对其进行测试。 备份和恢复是我认为最快的方式。