Как смоделировать абстрактный класс, используя шаблон декоратора и содержащий конструктор, который берет экземпляр себя
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
) не могут обойти проблему бесконечной рекурсии.
Ответы (2)
0 плюса
26 Репутация автора
Я согласен с Нкоси. Вам нужно передать любое (например, предложенное нулевое) значение base
, которое не вызовет исключения в FooBase
конструкторе.
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Вопросы из категории :
- c# Преобразовать десятичную в двойную?
- c# Как рассчитать чей-то возраст в C #?
- c# Как вы сортируете словарь по значению?
- c# В чем разница между int и Integer в Java и C #?
- unit-testing Каковы основные различия между TDD и BDD?
- unit-testing В чем разница между интеграционными и модульными тестами?
- unit-testing Как мне проверить приватную функцию или класс, который имеет закрытые методы, поля или внутренние классы?
- unit-testing Куда идут юнит-тесты Python?
- oop Передать по ссылке или передать по значению?
- oop Что такое инверсия контроля?
- oop Когда вы должны использовать «друг» в C ++?
- oop Предпочитаете композицию наследству?
- design-patterns Что такое MVP и MVC и в чем разница?
- design-patterns Двойная отправка в C #?
- design-patterns Заводская модель. Когда использовать фабричные методы?
- polymorphism Как реализуются виртуальные функции и vtable?
- polymorphism Try to describe polymorphism as easy as you can
- polymorphism В Java, как я могу вызвать метод базового класса из переопределяющего метода в производном классе?
- polymorphism Polymorphism - Define In Just Two Sentences