TransactionScope и DataContext

2

Я понимаю, что этот вопрос задавал раньше, но мне еще предстоит найти ответ, который действительно работает.

Моя проблема возникает, когда мои модульные тесты пытаются вызвать веб-службу, которая использует Linq для запроса базы данных.

unit test настроен следующим образом:

[TestInitialize]
public void SetUp()
{
    var scope = new TransactionScope(TransactionScopeOption.Required,TimeSpan.MaxValue);
    var database = new DatabaseDataContext();
}

[TestCleanup]
public void TearDown()
{
    scope.Dispose();
    database.Dispose();
}

[TestMethod]
public void GetCategoryList_Success()
{
    // create test data
    var result = service.GetItems();
}

Метод service.GetItems выглядит так:

try
{
    using (DatabaseDataContext database = new DatabaseDataContext())
    {
        var items = (from i in database.Items
                    select i).ToList<Items>();
        return items;
    }
}
catch (Exception ex)
{
   // log error
   return null;
}

Когда запрос Linq пытается выполнить, генерируется следующее исключение:

Операция недействительна для состояния транзакции.

Я полагаю, что это связано с вложенными транзакциями, но мне нужно сохранить транзакцию в открытом классе тестов, чтобы тестовые данные фактически не сохранялись в базе данных, и я могу избавиться от нее после запуска теста.

Кроме того, мой хостинг находится на общем экземпляре, поэтому я не могу напрямую вносить изменения в сервер.

Есть ли способ заставить это работать как есть или, альтернативно, есть альтернатива использованию TransactionScope в этом контексте?

Теги:
unit-testing
transactions
datacontext

1 ответ

0
Лучший ответ

Вы пытаетесь создать два соединения с одной базой данных в одном TransactionScope - одно соединение для тестового процесса и другое для процесса веб-службы. Это не работает, потому что в базе данных tranasctions из разных процессов явно не могут быть вложенными.

Вы должны изменить свой подход к тестированию здесь. Прочтите ответ Джона.

В качестве обходного пути вы можете заставить свой веб-сервис управлять транзакцией. Например, метод BeginGlobalTran должен создать глобальный объект Transaction (или TransactionScope) для веб-службы (хранимый в свойстве), все остальные его методы должны использовать этот объект (так что все другие транзакции вложены в глобальную транзакцию), другой метод говорит, что RollbackGlobalTran должен отменить эту глобальную транзакцию.
При этом это обходное решение, и это может вызвать некоторые неожиданные побочные эффекты (например, ошибка в методе сделает транзакцию "global" несовместимой, поэтому вам придется перезапустить ее, чтобы избежать дальнейших ошибок).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню