Вопрос:

Как смоделировать абстрактный класс, используя шаблон декоратора и содержащий конструктор, который берет экземпляр себя

c# unit-testing oop design-patterns polymorphism

25 просмотра

2 ответа

1 Репутация автора

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

Моя ситуация такова, что существует базовый класс

public abstract class FooBase
{
     public FooBase(FooBase inner) { /* ... */ }

     public virtual void DoSomething() { /* ... */ }
}

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

public class MockFoo : FooBase
{
    public MockFoo(...) : base(/*I have to put a FooBase in here*/) { /* ... */ }
}

Я не могу передать new MockFoo()INTO , baseпотому что это будет вызывать бесконечную рекурсию. Любые другие мои идеи (такие как создание другой MockFooOuter) не могут обойти проблему бесконечной рекурсии.

Автор: iQuery Источник Размещён: 10.08.2019 07:26

Ответы (2)


0 плюса

26 Репутация автора

Я согласен с Нкоси. Вам нужно передать любое (например, предложенное нулевое) значение base, которое не вызовет исключения в FooBaseконструкторе.

Автор: painacle Размещён: 10.08.2019 07:48

0 плюса

2911 Репутация автора

Если вы хотите протестировать декоратор, вам не нужно высмеивать декорированный метод, DoSomethingа весь декорированный класс.

Прежде всего, вам нужно исправить дизайн вашего класса и реализацию Decorator:
сейчас декоратор принимает экземпляр своего собственного типа декоратора в конструкторе, который не имеет смысла. Если это декоратор, он должен принять экземпляр декорированного типа.
Это означает, что вы должны ввести интерфейс для всех реализованных декорированных типов. В этом примере это называется IDecorated.

Цель состоит в том, чтобы иметь модульный тест, который выглядит следующим образом:

public class UnitTest
{
  public void TestDecorator()
  {
    IDecorated mockOfIDecorated = new DecoratedMock();
    DecoratorBase decoratorBaseTest = new DecoratorBaseTest(mockOfIDecorated);
    // Use decoratorBaseTest instance to test its public members
  }
}

Чтобы сделать издевательство возможным, представим интерфейс оформленного типа:

public interface IDecorated
{
  void DoSomething();
}

Это изменит и исправит сигнатуру конструктора типа декоратора. Также не делайте реализацию DoSomethingвиртуального декоратора, так как это может привести к нежелательному поведению (например, расширяющийся класс забывает делегировать вызовы экземпляру оформленного типа). Поэтому virtualбыл удален. Чтобы сделать расширенное поведение переопределенным для подтипов, просто добавьте абстрактный метод:

public abstract class DecoratorBase : IDecorated
{
  private IDecorated decorated;

  // The decorator should always accept an abstract type or interface of the type to be decorated
  public DecoratorBase(IDecorated decorated)
  {
    this.decorated = decorated;
  }

  public void DoSomething()
  {
    this.decorated.DoSomething();

    // Invoke the abstract member which adds customization  
    DoSomethingToExtendTheDecoratedBehavior();
  }

  public object DoSomethingDecoratorSpecific()
  {
  }

  protected abstract void DoSomethingToExtendTheDecoratedBehavior();
}

Издеваемый тип IDecorated. Вызов DoSomething()этого типа ничего не делает:

public class DecoratedMock : IDecorated
{
  #region Implementation of IDecorated

  public void DoSomething()
  {
    // Do nothing since this is a mock
  }

  #endregion
}

Поскольку вы не можете тестировать абстрактный класс напрямую, вам необходимо предоставить тестовую реализацию, которая может быть реализована тестовым классом:

public class DecoratorBaseTest : DecoratorBase
{
  public DecoratorBaseTest(IDecorated mockOfIDecorated) : base(mockOfIDecorated) { /* ... */ }

  #region Overrides of DecoratorBase

  protected override void DoSomethingToExtendTheDecoratedBehavior()
  {
    // Do nothing here because the unit test tests only public members
  }

  #endregion
}

Теперь, когда реализация Decorator исправлена, вы можете легко протестировать класс decorator.

Автор: BionicCode Размещён: 11.08.2019 08:59
Вопросы из категории :
32x32