Как вы издеваетесь над Запечатанным классом? - PullRequest
58 голосов
/ 09 августа 2008

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

Итак, как лучше всего издеваться над закрытыми классами?

Ответы на Java приветствуются . На самом деле, я ожидаю, что сообщество Java занимается этим дольше и может многое предложить.

Но вот некоторые мнения .NET:

Ответы [ 10 ]

18 голосов
/ 28 августа 2008

Для .NET вы можете использовать что-то вроде TypeMock , которое использует API профилирования и позволяет подключаться к вызовам практически ко всему.

13 голосов
/ 07 апреля 2010

Я считаю, что Родинок из Microsoft Research позволяет вам сделать это. Со страницы Кротов:

Родинки могут быть использованы для обхода любого .NET метод, в том числе не виртуальный / статический методы в запечатанных типах.

ОБНОВЛЕНИЕ: В готовящемся выпуске VS 11 появился новый фреймворк под названием "Подделки", предназначенный для замены родинок:

Fakes Framework в Visual Studio 11 - это следующее поколение Moles & Stubs, которое в конечном итоге заменит его. Однако Fakes отличается от Moles, поэтому переход от Moles к Fakes потребует некоторых изменений в вашем коде. Руководство по этой миграции будет доступно позже.

Требования : Visual Studio 11 Ultimate, .NET 4.5

7 голосов
/ 09 августа 2008

Мое общее правило заключается в том, что объекты, которые мне нужно смоделировать, также должны иметь общий интерфейс. Я думаю, что это правильно с точки зрения дизайна и делает тестирование намного проще (и обычно это то, что вы получаете, если делаете TDD). Подробнее об этом можно прочитать в блоге тестирования Google последнее сообщение (см. Пункт 9).

Кроме того, я работал в основном на Java в течение последних 4 лет, и я могу сказать, что могу рассчитывать с одной стороны, сколько раз я создал окончательный (запечатанный) класс. Другое правило: у меня всегда должна быть веская причина запечатать класс, а не запечатывать его по умолчанию.

4 голосов
/ 11 декабря 2009

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

Это также облегчает переключение моих зависимостей в долгосрочной перспективе.

4 голосов
/ 28 августа 2008

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

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

2 голосов
/ 12 мая 2015

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

  • Создать экземпляр запечатанного класса без вызова конструктора.
  • System.Runtime.Serialization.FormatterServices.GetUninitializedObject (instanceType);

  • Присвойте значения вашим свойствам / полям с помощью отражения

  • YourObject.GetType (). GetProperty ("PropertyName"). SetValue (dto, newValue, null);
  • YourObject.GetType (). GetField ("FieldName"). SetValue (dto, newValue);
1 голос
/ 04 апреля 2012

Несмотря на то, что он в настоящее время доступен только в бета-версии, я думаю, что стоит помнить о функции shim новой Fakes framework (часть Visual Studio 11 бета-версия).

Типы Shim предоставляют механизм для обхода любого метода .NET для определенного пользователем делегата. Типы Shim генерируются кодом генератором Fakes, и они используют делегаты, которые мы называем типами shim, для определения реализаций нового метода. Под капотом типы прокладок используют обратные вызовы, которые были введены во время выполнения в теле метода MSIL.

Лично я пытался использовать это для насмешки над методами в классах закрытых рамок, таких как DrawingContext.

1 голос
/ 07 апреля 2010

Совершенно разумно издеваться над запечатанным классом, потому что многие базовые классы запечатаны.

В моем случае я пытаюсь смоделировать класс MessageQueue .Net, чтобы я мог использовать мою изящную логику обработки исключений.

Если у кого-то есть идеи о том, как преодолеть ошибку 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;
    }
1 голос
/ 08 декабря 2009

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

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

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

Для получения дополнительной информации, пожалуйста, обратитесь к этой странице .

0 голосов
/ 09 августа 2008

Есть ли способ реализовать запечатанный класс из интерфейса ... и вместо этого смоделировать интерфейс?

Что-то во мне чувствует, что, во-первых, неправильно закрывать уроки, но это только я :) 1003 *

...