Как высмеивать запечатанный класс?

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

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

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

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

Не смейся! Вместо этого используйте композицию.

cregox 04.09.2013 23:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
66
1
38 532
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

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

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

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

Beep beep 22.11.2009 10:53
Ответ принят как подходящий

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

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

Я бы сказал, что у вас должна быть веская причина нет, чтобы запечатать класс. Оставление класса открытым означает, что вам нужно подумать о том, как он будет использоваться наследниками, что открывает шлюз решений по всему коду в классе (виртуальность, защищенные свойства или частные переменные-члены и т. д.). спроектируйте класс для наследования. Вы не должны иметь возможность расширять класс только ради расширения; вывод должен означать что-то конкретное для моделируемой проблемы. В противном случае отдавайте предпочтение композиции.

Bryan Watts 26.05.2009 18:46

Брайан, а как бы вы тогда издевались над закрытым классом? Я согласен с вами с теоретической точки зрения, но если вы пишете что-то, зависящее от вашего запечатанного класса, ваши тесты также зависят от запечатанного класса.

Beep beep 22.11.2009 10:48

@abyx: К сожалению, не всегда разработчик выбирает, является ли класс запечатанным или нет. Возьмем, например, System.Web.HttpServerUtility в ASP.NET ...

chiccodoro 07.07.2011 17:39

@BryanWatts Я категорически не согласен с этим. Запечатывание класса просто лишает кодировщиков возможности наследовать класс. Они могут найти его полезным способом, о котором вы даже не догадывались. Вам не нужно беспокоиться о том, что они как-то напортачят; это (вероятно) не ваша ответственность. Я бы вообще отказался от ключевого слова sealed.

Jez 22.04.2015 12:58

@Jez: Если бы я не рассматривал расширение при написании класса, по какой причине ему доверять?

Bryan Watts 23.04.2015 00:14

Полностью согласен с @Jez. Приятно видеть, что официальное руководство разделяет то же мнение: «НЕ запечатывайте классы без уважительной причины. Запечатывание класса из-за того, что вы не можете придумать сценарий расширяемости, не является хорошей причиной». (docs.microsoft.com/en-us/dotnet/standard/design-guidelines/‌…) Чтобы защитить методы от неправильного использования подклассом, просто оставьте их закрытыми. Разве этого не достаточно?

ZZY 18.10.2018 14:56

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

+1. Используйте правильные инструменты. Не позволяйте инструментам диктовать вам, как вы должны что-то делать. API-интерфейсы предназначены для людей, а не для инструментов - создавайте их как таковые. Используйте DI, интерфейсы и полную развязку там, где это имеет смысл, а не только потому, что вам это нужно для инструментов тестирования.

Pavel Minaev 30.10.2009 21:09

Павел - проблема в том, что «Правильный» путь в .NET обычно ведет вас по пути «Использовать TypeMock для тестирования». Путь, по которому доступен только один инструмент тестирования, тоже не кажется отличным.

Beep beep 22.11.2009 10:49

Некоторым людям может не понравиться платить 80 долларов в месяц за тестовый фреймворк.

Matt Grande 09.12.2009 22:16

Я думаю, что Moles позволяет вам работать с закрытыми классами - и если у вас есть подписка MSDN, это бесплатно.

Mathias 07.04.2010 00:13

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

Adam Ralph 17.05.2011 11:23

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

kodefuguru 30.04.2012 06:41

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

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

Не накладывать интерфейсы на все, что находится на виду, только потому, что они вам нужны из-за недостатков ваших инструментов тестирования, - это неплохой дизайн. На самом деле, как раз наоборот - это дизайн здравомыслящий, который касается дизайна, а не соответствия вашим инструментам. Клянусь, иногда мне кажется, что TDD, как это часто догматически практикуется, действительно следует называть «инструментальным дизайном». Также см. weblogs.asp.net/rosherove/archive/2008/01/17/…

Pavel Minaev 30.10.2009 21:08

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

Beep beep 22.11.2009 10:51

Я согласен с Брэдом здесь. Создание фиктивного объекта подразумевает, что вы тестируете публичное поведение этого типа. То есть вы конкретно говорите: «Мне нужно, чтобы общедоступный API этого объекта вел себя определенным образом». Это поведение независимый, однако упомянутый API реализован. Это означает, что у вас есть уже определенная (хотя и неявная) абстракция, которая должна вести себя определенным образом. В системе статических типов это должно быть явным путем создания абстрактного типа.

xofz 07.04.2010 00:18

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

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

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

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

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

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

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

В моем случае я пытаюсь издеваться над классом 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;
    }

Я нашел решение и разместил здесь: dotnetmonkey.net/post/Hard-to-Moq.aspx

Adam Lenda 07.04.2010 01:09

жаль, что страница мертва

Mihai Bratulescu 29.11.2018 00:38

спасибо за решение! страница все еще мертва

Viking 27.12.2018 15:53

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

Moles may be used to detour any .NET method, including non-virtual/static methods in sealed types.

Обновлено: в предстоящем выпуске VS 11 есть новый фреймворк под названием «Подделки», предназначенный для замены Moles:

The Fakes Framework in Visual Studio 11 is the next generation of Moles & Stubs, and will eventually replace it. Fakes is different from Moles, however, so moving from Moles to Fakes will require some modifications to your code. A guide for this migration will be available at a later date.

Requirements: Visual Studio 11 Ultimate, .NET 4.5

Хотя в настоящее время он доступен только в бета-версии, я думаю, что стоит помнить о функции прокладка нового Подделки рамки (часть бета-версии Visual Studio 11).

Shim types provide a mechanism to detour any .NET method to a user defined delegate. Shim types are code-generated by the Fakes generator, and they use delegates, which we call shim types, to specify the new method implementations. Under the hood, shim types use callbacks that were injected at runtime in the method MSIL bodies.

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

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

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

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

  • YourObject.GetType (). GetProperty ("Имя свойства"). SetValue (dto, newValue, null);
  • YourObject.GetType (). GetField ("Имя поля"). SetValue (dto, newValue);

Это единственное решение, которое имеет смысл и работает для имитации внутреннего материала Microsoft без добавления каких-либо дополнительных библиотек, таких как Fakes - спасибо!

Ben 28.10.2015 22:14

Другие вопросы по теме