TransactionScope不会在MSTest测试中回滚

时间:2011-02-07 23:13:51

标签: c# unit-testing transactions mstest vs-unit-testing-framework

我的测试中有以下基础对象

[TestClass]
public abstract class TestClassBase
{
    private TransactionScope _transactionScope;

    [TestInitialize]
    public virtual void TestInitialize()
    {
        _transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { Timeout = new TimeSpan(0, 10, 0) });
    }

    [TestCleanup]
    public virtual void TestCleanup()
    {
        _transactionScope.Dispose();
    }
}

我有一个测试,它执行以下操作

[TestMethod]
public void SaveToDatebaseTest(
{
     Program program = new Program();         
     program.Name = "Unit Test Program, I should not exists, when Test is done";
     ProgramManager programManager = new ProgramManager()
     programManager.Save(program);
}

当我运行测试时,记录仍然存在于数据库中。

我想避免在每个测试方法中使用TransactionScope

6 个答案:

答案 0 :(得分:3)

您需要更改TestCleanup方法,现在您处理TransactionScope,我相信它实际上是在进行隐式提交吗? (你会认为你需要调用Complete()吗?),因为没有错误它不会回滚事务。

试试这个

[TestCleanup]
public virtual void TestCleanup()
{
    // using System.Transactions;
    Transaction.Current.Rollback();
    _transactionScope.Dispose();
}

答案 1 :(得分:1)

我知道这个问题有点陈旧,但它可能会帮助那些将来可能/将要在这方面挣扎的人,就像我之前做的那样。所以,如果你正在使用

  • 实体框架
  • Nunit(v3)

以下代码无效。

class A
{
     private TransactionScope _trans;

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

     [TearDown]
     public void done()
     {
        if(_trans != null)
          _trans.Dispose();
     }

     [Test]
     public void doSomeDbWrite()
     {
         //your code to insert/update/delete data in db
     }
}

我在创建数据库上下文之前尝试(并且无法工作)创建TransactionScope,反之亦然。我认为它与EF本身有关,我认为它封装在他们自己的交易或其他任何事情中。我没有深入挖掘这一部分。无论如何,这是我用EF和事务做的,以确保在单元测试完成后你的单元测试DB是干净的。

class A
{
     private DbContext_DB;
     private DbContextTransaction _trans;

     [SetUp]
     public void setup()
     {
        DB = new DbContext();//create your db context
        _trans = DB.Database.BeginTransaction();
     }

     [TearDown]
     public void done()
     {
        _trans.Rollback();
        DB = null;
     }
}

希望此时能帮助其他人搜索: - )

答案 2 :(得分:1)

在 .NET Core 中,async Task [TestInitialize] 方法不受支持,会导致您描述的行为。

异步 ​​[TestInitialize] 方法似乎在与 [TestMethod] 本身不同的线程上下文中运行,即使 TransactionScopeAsyncFlowOption.Enabled 在 TransactionScope 的选项中设置。 Transaction.Current 在测试方法中将为 null,并且当 [TestCleanup] 处置 TransactionScope 时,任何更改都不会回滚。

不幸的是,there are no plans 支持 TestInitialize 方法中的异步流,尽管这适用于较旧版本的 .NET(至少是 .NET Framework 4.8)。

目前唯一的解决方法是使 [TestInitialize] 方法非异步并使 .Wait() / .Result 成为您的异步调用,但请对上面的 GitHub 问题点赞以表示对此功能的支持.

答案 3 :(得分:0)

如果您使用的是VS2005或VS2008(不确定2010年),则可以在测试方法完成后尝试MSTestExtensions进行自动数据库事务回滚。我已经将它与MS SQLServer一起使用,它运行的是分布式事务处理协调器服务。

我知道这可能不是您正在寻找的,但它可能对您的情况有所帮助。

答案 4 :(得分:0)

我认为你在这里要实现的是创建一个通用的Test类来实现初始化和清理,这样你就不必为每个测试重复那段代码,这是正确的吗?你甚至确定那些方法甚至被称为?请注意,您不能继承[TestInitialize]和[TestCleanup],因此您必须从sublcass调用这些方法。 (见https://stackoverflow.com/a/15946140/1638933)。

答案 5 :(得分:0)

我遇到相同的问题,但是我使用以下代码解决了该问题,也许它可以为您提供帮助:

    private readonly TransactionScope _scope;

    public MyTests()
    {
        var options = new TransactionOptions()
        {
            IsolationLevel = IsolationLevel.Snapshot
        };

        _scope = new TransactionScope(TransactionScopeOption.Required, options,  TransactionScopeAsyncFlowOption.Enabled);
      }

      [TestCleanup]
      public void Cleanup()
      {
          _scope.Dispose();
      }