Scott 的个人资料Software Development Wit...日志列表 工具 帮助

日志


3月22日

Database Unit Testing in .NET 2.0 with TransactionalFixture

I'm a big fan of unit testing.  I also tend to do a lot of persistence layer work.  So I often face the problem of restoring a test database to a known state before each test.
 
My favorite solution to this problem is to run each test inside a distributed transaction which is rolled back at the end, thereby returning the database to the initial state.  In most development environments, this is considerably faster than the canonical solution of dropping and recreating the test database for each test.
 
I first discovered the excellent distributed-transaction idea in this blog post by Roy Osherove.  He presents a special NUnit TestFixture called "DatabaseFixture" which codifies the approach using the test's SetUp and TearDown methods.  Personally, I prefer the name "TransactionalFixture" suggested by one of the commenters, because after all, the technique is equally applicable to tests using other transactional resources (most notably message queues).
 
I've been wanting to port this technique to the new System.Transactions classes available in .NET 2.0.  Tonight I finally got a chance to play with that and see how it comes out.  My new TransactionalFixture class (almost embarrassingly simple) is as follows:
 
using System;
using 
System.Transactions;
using 
NUnit.Framework;

namespace 
TransactionalFixtureLib
{
    [TestFixture]
    
public abstract class TransactionalFixture
    {
        
/// <summary>
        /// Transaction that we hold open for the duration of the test.
        /// </summary>
        
private System.Transactions.TransactionScope testTransaction;

        
[SetUp]
        
public void SetUp()
        {
            testTransaction 
= new TransactionScope();
        
}

        [TearDown]
        
public void TearDown()
        {
            testTransaction.Dispose()
;
        
}
    }
}
 
In a nutshell, if you make your NUnit tests extend TransactionalFixture, all of their operations on transactional resources will roll back at the end of the test.  Within the test itself, of course, the changes are visible, so you can perform any setup and verification that your test requires.
 
With regard to the implementation of TransactionalFixture, I would ordinarily strongly recommend against holding any disposable resources (like TransactionScope, or DbConnection) as member variables in a class that is not itself disposable.  However, in this case, we know that the TextFixture contract implemented by NUnit ensures that our resource will be cleaned up in the TearDown call.
 
Using System.Transactions has at least one substantial benefit over the .NET 1.x approach presented previously:  Your test library no longer needs to be hosted in a serviced component.  Among other things, that means it and everything it references no longer have to be strong-named.
 
I'll finish with a couple of usage notes that apply to both .NET 1.x and 2.0 versions of TransactionalFixture.  First, I said that when the outer transaction rolls back in TearDown, the database is restored to the initial state.  That's not entirely correct -- if you caused any auto-increment identity columns to come into play, they will continue to tick upward even as these transactions are rolled back.  Of course, your application should never care about this, but you should be aware lest anyone be surprised by this behavior.  Lastly, if you're debugging a transactional test, you'll want to make sure you're on an isolated database instance, because it's quite likely that many database resources will remain locked for the duration of a test.  In a team environment, it's a best practice to have everyone develop against their own version of the database anyway, and in that case, this is a non-issue.

评论

请稍候...
很抱歉,您输入的评论太长。请缩短您的评论。
您没有输入任何内容,请重试。
很抱歉,我们当前无法添加您的评论。请稍后重试。
若要添加评论,需要您的家长授予您相应权限。请求权限
您的家长禁用了评论功能。
很抱歉,我们当前无法删除您的评论。请稍后重试。
您已超过了一天之内允许提供的评论数上限。请在 24 小时后重试。
因为我们的系统表明您可能在向其他用户提供垃圾评论,您的帐户已禁用了评论功能。如果您认为我们错误地禁用了您的帐户,请联系 Windows Live 支持部门
完成下面的安全检查,您提供评论的过程才能完成。
您在安全检查中键入的字符必须与图片或音频中的字符一致。
McMasterSc​ott 在此页禁用了评论功能。

引用通告

此日志的引用通告 URL 是:
http://softwaredevscott.spaces.live.com/blog/cns!1A9E939F7373F3B7!155.trak
引用此项的网络日志