如何使用NUnittesting与数据库相关的代码?

我想用NUnit编写unit testing,命中数据库。 我想让每个testing的数据库处于一致的状态。 我认为交易可以让我“撤销”每一个testing,所以我search了一下,发现了2004 – 05年的几篇文章:

  • http://weblogs.asp.net/rosherove/archive/2004/07/12/180189.aspx
  • http://weblogs.asp.net/rosherove/archive/2004/10/05/238201.aspx
  • http://davidhayden.com/blog/dave/archive/2004/07/12/365.aspx
  • http://haacked.com/archive/2005/12/28/11377.aspx

这些似乎解决了实现NUnit的自定义属性,它构build了在每次执行testing之后回滚数据库操作的能力。

这很好,但…

  1. 这个function本身是否存在于NUnit的某个地方?
  2. 这种技术在过去的4年中有所改进吗?
  3. 这仍然是testing数据库相关代码的最好方法吗?

编辑:这不是我想特别testing我的DAL,而是我想testing与数据库交互的代码段。 对于这些testing是“不接触”和可重复的,如果我可以在每一个之后重置数据库,这将是非常棒的。

而且,我想把这个放到一个现在没有testing地点的现有项目中。 出于这个原因,我实际上无法为每个testing编写一个从头开始的数据库和数据。

NUnit现在有一个[Rollback]属性,但是我更喜欢用不同的方式来做。 我使用TransactionScope类。 有几种方法可以使用它。

[Test] public void YourTest() { using (TransactionScope scope = new TransactionScope()) { // your test code here } } 

既然你没有告诉TransactionScope提交它会自动回滚。 即使断言失败或引发其他exception,它也可以工作。

另一种方法是使用[SetUp]创buildTransactionScope和[TearDown]来调用Dispose。 它删除了一些代码重复,但完成相同的事情。

 [TestFixture] public class YourFixture { private TransactionScope scope; [SetUp] public void SetUp() { scope = new TransactionScope(); } [TearDown] public void TearDown() { scope.Dispose(); } [Test] public void YourTest() { // your test code here } } 

这与单个testing中的使用语句一样安全,因为NUnit将保证调用TearDown。

说了一切,我认为testing打到数据库不是真正的unit testing。 我仍然写他们,但我认为他们作为集成testing。 我仍然认为它们提供了价值。 我经常使用它们的一个地方是testingLINQ to SQL代码。 我不使用devise师。 我手写DTO和属性。 我知道错了。 集成testing有助于发现我的错误。

我刚刚去了一个.NET用户组,主持人说他在testing设置和拆卸中使用了SQLlite,并使用了内存选项。 他不得不把连接搞得一团糟,明确地破坏连接,但每次都会给一个干净的数据库。

http://houseofbilz.com/archive/2008/11/14/update-for-the-activerecord-quotmockquot-framework.aspx

对于这种testing,我尝试了NDbUnit(与NUnit一起工作)。 如果内存服务,它是来自Java平台的DbUnit的一个端口。 对于你正在做的事情,它有很多漂亮的命令。 该项目似乎搬到了这里:

http://code.google.com/p/ndbunit/

(它曾经在http://ndbunit.org )。

来源似乎可以通过这个链接: http : //ndbunit.googlecode.com/svn/trunk/

我会称这些集成testing,但不pipe。 我为这样的testing所做的工作是在testing类中使用我的设置方法,在每次testing之前清除所有感兴趣的表。 我通常手写SQL来做到这一点,所以我没有使用被testing的类。

一般来说,我依赖一个ORM作为我的数据层,因此我不会在那里编写unit testing。 我不觉得需要unit testing我不写的代码。 对于我在图层中添加的代码,我通常使用dependency injection来抽象出与数据库的实际连接,以便在testing我的代码时,它不会触及实际的数据库。 结合模拟框架来获得最佳结果。

考虑创build一个数据库脚本,以便您可以从NUnit自动运行,也可以手动进行其他types的testing。 例如,如果使用Oracle,则从NUnit中启动SqlPlus并运行脚本。 这些脚本通常写得更快,而且更易于阅读。 另外,非常重要的是,从Toad或同等版本运行SQL比从代码运行SQL或从代码执行ORM更具启发性。 通常我会创build一个设置和拆卸脚本,并把它们设置和拆卸方法。

你是否应该unit testing通过数据库是另一个讨论。 我相信这样做通常是有道理的。 对于许多应用程序来说,数据库是绝对的行动中心,逻辑高度设置的基础,所有其他技术和语言和技术都是通过鬼魂。 随着function语言的兴起,我们开始认识到像JavaScript这样的SQL实际上是一种很好的语言,这些年来在我们的鼻子下是正确的。

就像在旁边,Linq to SQL(我从概念上来说,虽然从未使用过)几乎在我看来像是从代码中做原始SQL,而不承认我们正在做的事情。 有些人喜欢SQL,知道他们喜欢,喜欢的人也不喜欢。 🙂