TransactionScope не выполняет откат в тесте MSTest

У меня есть следующий базовый объект в моих тестах

[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 в каждом методе тестирования.


person Brian    schedule 07.02.2011    source источник


Ответы (6)


Вам нужно изменить свой метод TestCleanup, прямо сейчас вы избавляетесь от TransactionScope, я полагаю, что на самом деле он выполняет неявную фиксацию? (хотя вы могли бы подумать, что вам нужно будет вызвать Complete()?), поскольку ошибок нет, это не откат транзакции.

попробуй это

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

я знаю, что этот вопрос довольно старый, но он может помочь кому-то, кто может / будет бороться с этим в будущем, как я только что сделал ранее. поэтому, если вы используете

  • Структура сущности
  • Нунит (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 и транзакциями, чтобы убедиться, что ваша тестовая БД чиста после завершения модульного теста.

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;
     }
}

Надеюсь, это поможет другим, кто ищет это сейчас :-)

person Anthony    schedule 08.11.2017

В .NET Core методы async Task [TestInitialize] не поддерживаются и приведут к описанному вами поведению.

Асинхронные методы [TestInitialize], по-видимому, выполняются в контексте потока, отличном от самого [TestMethod], даже если TransactionScopeAsyncFlowOption.Enabled задано в параметрах TransactionScope. Transaction.Current будет иметь значение null в тестовом методе, и любые изменения не будут отменены, когда [TestCleanup] удалит TransactionScope.

К сожалению, нет планов по поддержке асинхронного потока в методах TestInitialize, несмотря на то, что это работало в более старых версиях. .NET (как минимум .NET Framework 4.8).

Единственный обходной путь в настоящее время — сделать метод [TestInitialize] неасинхронным и .Wait() / .Result ваши асинхронные вызовы, но, пожалуйста, проголосуйте за проблему GitHub выше, чтобы показать поддержку этой функции.

person ajbeaven    schedule 18.03.2021
comment
Это было проблемой до того, как dotnet core и async - person Brian; 19.03.2021
comment
Да, я уверен, что это было. - person ajbeaven; 21.03.2021

Если вы используете VS2005 или VS2008 (не уверен насчет 2010), вы можете попробовать MSTestExtensions для автоматического отката транзакции базы данных после Методы испытаний завершены. Я использовал его с MS SQLServer, и служба координатора распределенных транзакций работает.

Я знаю, что это может быть не совсем то, что вы ищете, но это может помочь в вашей ситуации.

person Matt    schedule 08.02.2011

Я думаю, что вы пытаетесь достичь здесь, чтобы создать общий класс Test, который реализует инициализацию и очистку, поэтому вам не нужно повторять этот код для каждого теста, это правильно? Вы вообще уверены, что эти методы вообще вызываются? Имейте в виду, что вы не можете создавать подклассы [TestInitialize] и [TestCleanup], поэтому вам придется вызывать эти методы из подкласса. (См. https://stackoverflow.com/a/15946140/1638933).

person José Ramón    schedule 21.04.2015

У меня такая же проблема, но я использовал следующий код для решения проблемы. Может быть, это может вам помочь:

    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();
      }
person Luis Fernando Camacho Camacho    schedule 12.08.2019