TransactionScope вызывает TransactionManagerCommunicationException при использовании для модульных тестов БД - PullRequest
5 голосов
/ 19 января 2011

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

После некоторых исследований я предложил подход TransactionScope в моем тестовом проекте Visual Studio 2010, например

using( new TransactionScope())
{
    using( SqlConnection connection = new SqlConnection("someConnectionString"))
    {
        connection.Open();
        using( SqlCommand command = new SqlCommand( "some sql", connection ))
        {
            // Do some database stuff...
        }
     }
}

Теперь это работает нормально, пока я помещаю все это в один метод тестирования, т. Е. Все мои изменения в базе данных автоматически откатываются после завершения использования блока для TransactionScope.

Моя проблема сейчас в том, что я хотел бы сделать кое-что из базы данных в ClassInitialize, поэтому мне нужно делать это только один раз для каждого класса теста, а не для каждого метода теста. Когда я создаю открытое свойство TransactionScope и назначаю ему экземпляр TransactionScope в методе ClassInitialize, это работает нормально. Как только я выполняю какие-либо вещи, связанные с базой данных, в одном из моих методов тестирования, я сталкиваюсь с TransactionManagerCommunicationException в этом методе.

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

EDIT

Ниже приведена выдержка из кода, надеюсь, это даст достаточно информации:

public TransactionScope Scope { get; set; }

[ClassInitialize]
public static void ClassInitialize( TestContext testContext )
{
    Scope = new TransactionScope();
    // Do some db set up stuff, e.g. create records used for tests etc.
}

[ClassCleanup]
public static void ClassCleanup()
{
    Scope.Dispose();
}

[TestMethod]
public void MyTestMethod()
{
    using( SqlConnection connection = new SqlConnection( "someConnectionString" ) )
    {
        DataTable result = new DataTable();
        using( SqlCommand command = new SqlCommand( "spName", connection ) )
        {
            command.CommandType = CommandType.StoredProcedure;
            using( SqlDataAdapter adapter = new SqlDataAdapter() )
            {
                adapter.SelecteCommand = command;
                // The next line causes the exception to be thrown
                adapter.Fill( result );
            }
        }

        // Assertions against DataTable result
    }
}

Исключение составляет


Исключением TransactionManagerCommunicationException является код пользователя Доступ к сети для диспетчера распределенных транзакций (MSDTC) отключен. Включите DTC для доступа к сети в конфигурации безопасности для MSDTC с помощью инструмента администрирования служб компонентов.


Я понимаю, что я мог попытаться изменить настройки, но я не понимаю, почему я получаю исключение для начала - что отличается от наличия кода выше в одном (тестовом) методе?

Заранее спасибо и

С наилучшими пожеланиями

G.

Ответы [ 3 ]

4 голосов
/ 19 января 2011

Ваше исключение говорит о том, что MSDTC не включен.Я предполагаю, что когда вы использовали TransactionScope по отдельности, он просто создавал локальные транзакции SQL - для которых не требуется код DTC.Однако при совместном использовании TransactionScope по нескольким соединениям транзакция «переводится» в распределенную транзакцию через DTC, который вы, возможно, не включили.

Попробуйте включить сетевой доступ на MSDTC на локальном компьютере исервер.Шаги для этого немного различаются в зависимости от вашей ОС. Вот как это сделать в Win 2003 Server . Вот ссылка на Win 2008 .Обратите внимание, что вам, вероятно, потребуется включить DTC и через брандмауэры (объяснение в последней ссылке ...)

0 голосов
/ 19 января 2011

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

Я использую NUNit, но принцип должен быть таким же для MSTest. Подсказка заключается в том, что SetUp и TearDown выполняются один раз до и после каждого модульного теста, чтобы обеспечить изоляцию между модульными тестами.

Кроме того, как отмечает @blech, для работы этого решения должна быть запущена служба координатора распределенных транзакций Microsoft (MSDTC).

0 голосов
/ 19 января 2011

Вы можете создать свою настройку примерно так:

void Main()
{
   using(new SetupTransaction())
   {
    //Your test
   }
}

public class SetupTransaction : IDisposable
{
    private TransactionScope transaction;

    public SetupTransaction()
    {
        transaction = new TransactionScope();
        //Do your stuff here
    }

    public void Dispose()
    {
        transaction.Dispose();
    }
}

Что касается ошибки, которую вы получаете, не могли бы вы опубликовать, как именно вы используете свою реализацию?

...