我们没有使用TDD,所以单元测试麻烦的是准备测试的基础数据。我们现在是使用内存仓储来做单元测试,要为每个仓储都构造基础数据,非常麻烦。

  前几天看xunit的源码,看到AutoRollbackAttribute这个特性,异常的兴奋 ^_^。怎么忘了用事务的自动回滚呢?

  我们看AutorollbackAttribute的具体实现:

public class AutoRollbackAttribute : BeforeAfterTestAttribute
{
    IsolationLevel isolationLevel = IsolationLevel.Unspecified;
    TransactionScope scope;
    TransactionScopeOption scopeOption = TransactionScopeOption.Required;
    long timeoutInMS = -1;

     /// <summary>
    /// Gets or sets the isolation level of the transaction.
    /// Default value is <see cref="IsolationLevel"/>.Unspecified.
    /// </summary>
    public IsolationLevel IsolationLevel
    {
        get { return isolationLevel; }
        set { isolationLevel = value; }
    }

     /// <summary>
    /// Gets or sets the scope option for the transaction.
    /// Default value is <see cref="TransactionScopeOption"/>.Required.
    /// </summary>
    public TransactionScopeOption ScopeOption
    {
        get { return scopeOption; }
        set { scopeOption = value; }
    }

     /// <summary>
    /// Gets or sets the timeout of the transaction, in milliseconds.
    /// By default, the transaction will not timeout.
    /// </summary>
    public long TimeoutInMS
    {
        get { return timeoutInMS; }
        set  { timeoutInMS = value; }
    }

     /// <summary>
    /// Rolls back the transaction.
    /// </summary>
    public override void After(MethodInfo methodUnderTest)
    {
        scope.Dispose();
    }

     /// <summary>
    /// Creates the transaction.
    /// </summary>
    public override void Before(MethodInfo methodUnderTest)
    {
        TransactionOptions options = new TransactionOptions();
        options.IsolationLevel = isolationLevel;
        if (timeoutInMS > 0)
           options.Timeout = new TimeSpan(timeoutInMS * 10);
        scope = new TransactionScope(scopeOption, options);
    }
}

  这里使用了.Net Framework自带的TransactionScope。TransactionScope在.NET 2.0中已经有了,可用于分布式事务。用这种方法来做数据的自动回滚也有一些不足:

  1、数据库要支持事务。

  2、内部数据库操作的逻辑里没有事务的实现。

  很庆幸的是我们的项目正好都满足上面的2点,不足的是mongodb不支持事务。所以需要混合仓储实现了,事务数据库使用真实的仓储,mongodb使用内存仓储。