Как вы издеваетесь над Закрытым классом?
-
08-06-2019 - |
Вопрос
Издевательские закрытые классы это может быть настоящей болью.В настоящее время я выступаю за Шаблон адаптера чтобы справиться с этим, но что-то в just продолжает казаться странным.
Итак, как лучше всего имитировать закрытые классы?
Ответы на Java более чем приветствуются.На самом деле, я бы предположил, что сообщество Java занимается этим дольше и может многое предложить.
Но вот некоторые из них .СЕТЕВЫЕ мнения:
Решение
Мое общее эмпирическое правило заключается в том, что объекты, которые мне нужно смоделировать, также должны иметь общий интерфейс.Я думаю, что это правильно с точки зрения дизайна и значительно упрощает тесты (и обычно это то, что вы получаете, если выполняете TDD).Подробнее об этом можно прочитать в блоге Google по тестированию последнее сообщение (См. пункт 9).
Кроме того, последние 4 года я работал в основном на Java и могу сказать, что могу по пальцам одной руки пересчитать, сколько раз я создавал окончательный (запечатанный) класс.Другое правило здесь заключается в том, что у меня всегда должна быть веская причина запечатать класс, в отличие от того, чтобы запечатывать его по умолчанию.
Другие советы
Для .NET вы могли бы использовать что-то вроде Типовой блок, который использует API профилирования и позволяет подключаться к вызовам практически к чему угодно.
Я верю, что Родинки, от Microsoft Research, позволяет вам это сделать.Со страницы "Кроты":
Родинки могут использоваться для обхода любого метода .NET , включая невиртуальные / статические методы в закрытых типах.
Обновить: в предстоящем выпуске VS 11 появится новый фреймворк под названием "Fakes", который предназначен для замены Moles:
Тот Самый Подделывает фреймворк в Visual Studio 11 это следующее поколение Moles & Stubs, которое в конечном итоге заменит его.Однако Fakes отличается от Moles, поэтому переход от Moles к Fakes потребует некоторых изменений в вашем коде.Руководство по этой миграции будет доступно позднее.
Требования:Visual Studio 11 Ultimate, .NET 4.5
Проблема с TypeMock в том, что он оправдывает плохой дизайн.Теперь я знаю, что это часто бывает чей-то еще плохой дизайн, который он скрывает, но включение его в ваш процесс разработки может очень легко привести к разрешению ваших собственных плохих проектов.
Я думаю, что если вы собираетесь использовать макет фреймворка, вам следует использовать традиционный фреймворк (например, Moq) и создать изолирующий слой вокруг недоступной для блокировки вещи, а вместо этого имитировать изолирующий слой.
Я почти всегда избегаю наличия зависимостей от внешних классов глубоко в моем коде.Вместо этого я бы предпочел использовать адаптер / мост для общения с ними.Таким образом, я имею дело со своей семантикой, и трудность перевода изолирована в одном классе.
Это также облегчает переключение моих зависимостей в долгосрочной перспективе.
Недавно я столкнулся с этой проблемой, и после чтения / поиска в Интернете кажется, что нет простого способа обойти это, кроме как использовать другой инструмент, как упомянуто выше.Или грубо обращался с вещами, как это делал я:
- Создайте экземпляр запечатанного класса без вызова конструктора.
Система.Среда выполнения.Сериализация.Службы форматирования.Получаем uninitializedobject(instanceType);
Присваивайте значения своим свойствам / полям с помощью отражения
- YourObject.GetType().getProperty("Имя свойства").setValue(dto, newValue, null);
- YourObject.GetType().getField("Имя_поля").setValue(dto, новое значение);
Обычно я иду по пути создания интерфейса и класса адаптера / прокси, чтобы облегчить издевательство над запечатанным типом.Тем не менее, я также экспериментировал с пропуском создания интерфейса и созданием незапечатанного типа прокси с помощью виртуальных методов.Это хорошо работало, когда прокси-сервер действительно является естественным базовым классом, который инкапсулирует и использует часть закрытого класса.
Когда я имел дело с кодом, который требовал такой адаптации, мне надоело выполнять одни и те же действия для создания интерфейса и типа прокси, поэтому я внедрил библиотеку для автоматизации задачи.
Код несколько более сложный, чем пример, приведенный в статье, на которую вы ссылаетесь, поскольку он создает сборку (вместо исходного кода), позволяет выполнять генерацию кода для любого типа и не требует такой большой настройки.
Для получения дополнительной информации, пожалуйста, обратитесь к эта страница.
Совершенно разумно имитировать закрытый класс, потому что многие классы фреймворка являются закрытыми.
В моем случае я пытаюсь издеваться.Класс MessageQueue от Net, чтобы я мог использовать свою логику обработки исключений TDD.
Если у кого-нибудь есть идеи о том, как преодолеть ошибку Moq, касающуюся "Недопустимой настройки для переопределяемого элемента", пожалуйста, дайте мне знать.
код:
[TestMethod]
public void Test()
{
Queue<Message> messages = new Queue<Message>();
Action<Message> sendDelegate = msg => messages.Enqueue(msg);
Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate =
(v1, v2) =>
{
throw new Exception("Test Exception to simulate a failed queue read.");
};
MessageQueue mockQueue = QueueMonitorHelper.MockQueue(sendDelegate, receiveDelegate).Object;
}
public static Mock<MessageQueue> MockQueue
(Action<Message> sendDelegate, Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate)
{
Mock<MessageQueue> mockQueue = new Mock<MessageQueue>(MockBehavior.Strict);
Expression<Action<MessageQueue>> sendMock = (msmq) => msmq.Send(It.IsAny<Message>()); //message => messages.Enqueue(message);
mockQueue.Setup(sendMock).Callback<Message>(sendDelegate);
Expression<Func<MessageQueue, Message>> receiveMock = (msmq) => msmq.Receive(It.IsAny<TimeSpan>(), It.IsAny<MessageQueueTransaction>());
mockQueue.Setup(receiveMock).Returns<TimeSpan, MessageQueueTransaction>(receiveDelegate);
return mockQueue;
}
Хотя в настоящее время он доступен только в бета-версии, я думаю, что стоит иметь в виду прокладка особенность нового Подделки фреймворка (часть Visual Studio 11 Бета-версия).
Типы прокладок предоставляют механизм для перехода от любого метода .NET к определяемому пользователем делегату.Типы прокладок генерируются в коде генератором подделок, и они используют делегаты, которые мы называем типами прокладок, для указания реализаций новых методов.Под капотом типы прокладок используют обратные вызовы, которые были введены во время выполнения в тела метода MSIL.
Лично я рассматривал возможность использования этого для моделирования методов в закрытых классах фреймворка, таких как DrawingContext.
Есть ли способ реализовать закрытый класс из интерфейса?..и вместо этого издеваться над интерфейсом?
Что-то во мне подсказывает, что наличие закрытых классов изначально неправильно, но это только я :)