Поблочное тестирование использование TransactionScope

arr теперь является зависимым именем. Это зависит от T. Что, если есть T, для которого Base<T> специализирован, чтобы не иметь arr? В частности, из [temp.dep]:

В определении шаблона класса или класса область зависимого базового класса (14.6.2.1) не рассматривается при неквалифицированном поиске имени либо в точка определения шаблона класса или члена или во время создания шаблона или члена класса.

Base<T> - зависимый базовый класс - он зависит от параметра шаблона T , поэтому его область не рассматривается во время поиска unqualified . Для этого нужно использовать квалифицированный поиск . То есть либо имя класса:

parr = &Base<T>::arr[0];

, либо просто с помощью this:

parr = &this->arr[0];
27
задан Randolpho 9 March 2009 в 15:56
поделиться

3 ответа

Я сейчас сижу с той же проблемой и мне, кажется, существует два решения:

  1. не решают проблему.
  2. Создают абстракции для существующих классов, который следует за тем же шаблоном, но является mockable/stubable.

Редактирование: я создал CodePlex-проект для этого теперь: http://legendtransactions.codeplex.com/

я склоняюсь к созданию ряда интерфейсов для работы с транзакциями и реализации по умолчанию, которая делегирует к Системе. Реализации транзакции, что-то как:

public interface ITransactionManager
{
    ITransaction CurrentTransaction { get; }
    ITransactionScope CreateScope(TransactionScopeOption options);
}

public interface ITransactionScope : IDisposable
{
    void Complete();  
}

public interface ITransaction
{
    void EnlistVolatile(IEnlistmentNotification enlistmentNotification);
}

public interface IEnlistment
{ 
    void Done();
}

public interface IPreparingEnlistment
{
    void Prepared();
}

public interface IEnlistable // The same as IEnlistmentNotification but it has
                             // to be redefined since the Enlistment-class
                             // has no public constructor so it's not mockable.
{
    void Commit(IEnlistment enlistment);
    void Rollback(IEnlistment enlistment);
    void Prepare(IPreparingEnlistment enlistment);
    void InDoubt(IEnlistment enlistment);

}

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

Примечание, что это не полное определение интерфейсов как раз, чтобы дать Вам большое изображение.

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

public interface ITransactionManager
{
    ITransaction CurrentTransaction { get; }
    ITransactionScope CreateScope(TransactionScopeOption options);
}

public class TransactionManager : ITransactionManager
{
    public ITransaction CurrentTransaction
    {
        get { return new DefaultTransaction(Transaction.Current); }
    }

    public ITransactionScope CreateScope(TransactionScopeOption options)
    {
        return new DefaultTransactionScope(new TransactionScope());
    }
}

public interface ITransactionScope : IDisposable
{
    void Complete();  
}

public class DefaultTransactionScope : ITransactionScope
{
    private TransactionScope scope;

    public DefaultTransactionScope(TransactionScope scope)
    {
        this.scope = scope;
    }

    public void Complete()
    {
        this.scope.Complete();
    }

    public void Dispose()
    {
        this.scope.Dispose();
    }
}

public interface ITransaction
{
    void EnlistVolatile(Enlistable enlistmentNotification, EnlistmentOptions enlistmentOptions);
}

public class DefaultTransaction : ITransaction
{
    private Transaction transaction;

    public DefaultTransaction(Transaction transaction)
    {
        this.transaction = transaction;
    }

    public void EnlistVolatile(Enlistable enlistmentNotification, EnlistmentOptions enlistmentOptions)
    {
        this.transaction.EnlistVolatile(enlistmentNotification, enlistmentOptions);
    }
}


public interface IEnlistment
{ 
    void Done();
}

public interface IPreparingEnlistment
{
    void Prepared();
}

public abstract class Enlistable : IEnlistmentNotification
{
    public abstract void Commit(IEnlistment enlistment);
    public abstract void Rollback(IEnlistment enlistment);
    public abstract void Prepare(IPreparingEnlistment enlistment);
    public abstract void InDoubt(IEnlistment enlistment);

    void IEnlistmentNotification.Commit(Enlistment enlistment)
    {
        this.Commit(new DefaultEnlistment(enlistment));
    }

    void IEnlistmentNotification.InDoubt(Enlistment enlistment)
    {
        this.InDoubt(new DefaultEnlistment(enlistment));
    }

    void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
    {
        this.Prepare(new DefaultPreparingEnlistment(preparingEnlistment));
    }

    void IEnlistmentNotification.Rollback(Enlistment enlistment)
    {
        this.Rollback(new DefaultEnlistment(enlistment));
    }

    private class DefaultEnlistment : IEnlistment
    {
        private Enlistment enlistment;

        public DefaultEnlistment(Enlistment enlistment)
        {
            this.enlistment = enlistment;
        }

        public void Done()
        {
            this.enlistment.Done();
        }
    }

    private class DefaultPreparingEnlistment : DefaultEnlistment, IPreparingEnlistment
    {
        private PreparingEnlistment enlistment;

        public DefaultPreparingEnlistment(PreparingEnlistment enlistment) : base(enlistment)
        {
            this.enlistment = enlistment;    
        }

        public void Prepared()
        {
            this.enlistment.Prepared();
        }
    }
}

Вот пример класса, который зависит от ITransactionManager для обработки, это - транзакционная работа:

public class Foo
{
    private ITransactionManager transactionManager;

    public Foo(ITransactionManager transactionManager)
    {
        this.transactionManager = transactionManager;
    }

    public void DoSomethingTransactional()
    {
        var command = new TransactionalCommand();

        using (var scope = this.transactionManager.CreateScope(TransactionScopeOption.Required))
        {
            this.transactionManager.CurrentTransaction.EnlistVolatile(command, EnlistmentOptions.None);

            command.Execute();
            scope.Complete();
        }
    }

    private class TransactionalCommand : Enlistable
    {
        public void Execute()
        { 
            // Do some work here...
        }

        public override void Commit(IEnlistment enlistment)
        {
            enlistment.Done();
        }

        public override void Rollback(IEnlistment enlistment)
        {
            // Do rollback work...
            enlistment.Done();
        }

        public override void Prepare(IPreparingEnlistment enlistment)
        {
            enlistment.Prepared();
        }

        public override void InDoubt(IEnlistment enlistment)
        {
            enlistment.Done();
        }
    }
}
28
ответ дан abatishchev 14 October 2019 в 14:28
поделиться

Я - Java-разработчик, таким образом, я не уверен в деталях C#, но мне необходимостью в двух модульных тестах здесь кажется.

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

второй должен быть "wonky" версией, которая делает деятельность InsertFoo и затем выдает исключение прежде, чем делать попытку InsertBar. Успешный тест покажет, что исключение было выдано и что ни объекты Нечто ни Панели не посвятили себя базе данных.

, Если бы оба из них передают, я сказал бы, что Ваш TransactionScope работает, как он должен.

3
ответ дан duffymo 14 October 2019 в 14:28
поделиться

Игнорирование, является ли этот тест хорошей вещью или нет....

Очень грязный взлом должен проверить ту Транзакцию. Текущий не является пустым.

Это не 100%-й тест, так как кто-то мог использовать что-то другое, чем TransactionScope для достижения этого, но он должен принять меры против очевидного, 'не потрудился иметь транзакцию' части.

Другая опция состоит в том, чтобы сознательно попытаться создать новый TransactionScope с несовместимым уровнем изоляции к тому, что/должно использоваться и TransactionScopeOption.Required. Если это успешно выполняется вместо того, чтобы бросить ArgumentException не было транзакции. Это требует, чтобы Вы знали, что конкретный IsolationLevel не использован (что-то как Chaos - потенциальный выбор)

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

5
ответ дан abatishchev 14 October 2019 в 14:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: