【问题标题】:Unit Testing Legacy Code without DI没有 DI 的单元测试遗留代码
【发布时间】:2014-08-05 15:05:46
【问题描述】:
我们正在尝试将单元测试添加到我们的业务层中。技术栈是asp.net web forms、WCF、ADO.Net调用存储过程)。业务层在数据类上调用静态方法,不做大量改动就很难引入DI。
这可能不是传统的方法,但我正在考虑将数据库保留在单元测试(依赖关系)中,但将其用作测试数据库......使用现有的冻结数据库或已模拟表中的数据。我想知道使用像 Mocks 一样使用存储过程的测试数据库的可行性。无需复制整个数据库,只需创建由存储过程命名的表名。
存储过程只会调用一个表,并返回静态数据......本质上,试图用类似 Moq 的东西来模拟 Mocking 数据的功能,但从数据库的角度来看。
任何人都可以推荐任何在测试中包含数据库且仍具有确定性的设计吗?
【问题讨论】:
标签:
c#
unit-testing
legacy-code
【解决方案1】:
如果您想在测试中使用数据库并让一切都具有确定性,那么您需要每个测试都有自己的数据库,这意味着为每个测试创建(并可能填充)一个新数据库。
根据您的 DB 层创建连接的方式,这是可行的。我做了类似的事情,在测试设置中使用 localDb 生成数据库,名称为 GUID,然后在测试结束时再次删除数据库。
它最终会相当慢(不足为奇),但在 Ram 磁盘驱动器上创建 DB 有助于解决这个问题。
这对于空 dbs 工作正常,然后具有由 EF 创建的架构,但如果您需要数据库中的一组固定数据,那么您可能需要在测试设置中从备份中恢复它
【解决方案2】:
在我看来,设置您的存储过程以在每次测试调用它们时执行您希望它们执行的操作将是大量工作,并且您最终仍然会遇到数据库始终存在的速度问题.我建议您改为执行以下一项或两项操作:
- 使用TypeMock,它有一个强大的隔离工具。它基本上会更改您的编译以使您的单元测试甚至可以模拟静态方法。
- 尝试创建“验收测试”,而不仅仅是单元测试,它专注于模仿完整的用户体验:登录、创建对象、查看对象(验证对象看起来是否正确)、更新对象、再次查看对象(同上)、删除对象(验证对象是否已删除)。通过设置此特定测试所需的所有对象开始这些测试中的每一个,并以删除所有这些对象结束,以便其他测试可以根据假定的开始状态运行。
第一种方法为您提供真正“单元”测试的速度和可模拟性,而第二种方法允许您执行更多代码,从而增加捕获错误的可能性,即使在存储过程之类的事情中也是如此。