Использование PowerMock или сколько вы позволяете вашим тестам влиять на ваш дизайн?
Я уже много лет болею за EasyMock, и благодаря SO я столкнулся с ссылками на PowerMock и его способность издеваться над конструкторами и статическими методами, из-за которых возникают проблемы при переоснащении тестов на устаревшую кодовую базу.
Очевидно, что одним из огромных преимуществ модульного тестирования (и TDD) является то, как он приводит (усиливает?) гораздо более чистый дизайн, и мне кажется, что введение PowerMock может отвлечь его. Я бы увидел, что это в основном проявляется как:
- Возвращаясь к инициализации коллабораторов, а не к их вложению
- Использование статики, а не использование метода соавтором
В дополнение к этому, что-то не совсем подходит ко мне, когда мой код управляется байт-кодом для теста. Я не могу дать конкретную причину этого, просто потому, что это заставляет меня чувствовать себя немного неловко, как для теста, а не для производства.
На моем нынешнем концерте мы действительно настаиваем на модульных тестах, чтобы люди могли улучшить свои методы кодирования, и похоже, что введение PowerMock в уравнение может позволить людям немного пропустить этот шаг, и поэтому я не хочу начинать используй это. Сказав это, я действительно смогу понять, где его использование может сократить объем рефакторинга, который необходимо выполнить, чтобы начать тестирование класса.
Я полагаю, что мой вопрос в том, какие люди используют PowerMock (или любую другую подобную библиотеку) для этих функций, могли бы вы использовать их и сколько всего вы хотите, чтобы ваши тесты влияли на ваш дизайн?
Ответы
Ответ 1
Я думаю, вы правы, чтобы беспокоиться. Рефакторинг устаревшего кода, подлежащего тестированию, в большинстве случаев не является , что трудно, когда вы узнали, как это сделать.
Лучше идти немного медленнее и иметь благоприятную среду для обучения, чем делать короткие сокращения и изучать плохие привычки.
(И я просто прочитал это и почувствовал, что это актуально.)
Ответ 2
Я должен категорически не соглашаться с этим вопросом.
Нет никакого оправдания для насмешливого инструмента, который ограничивает выбор дизайна. Это не просто статические методы, которые исключаются с помощью EasyMock, расширения класса EasyMock, jMock, Mockito и других. Эти инструменты также не позволяют вам объявлять классы и методы final
, и это само по себе очень плохо. (Если вам нужен один авторитетный источник, который защищает использование final
для классов и методов, см. Книгу "Эффективная Java" или смотрите эту презентацию от автора.)
И "инициализация коллаборационистов, а не их внедрение" часто является лучшим дизайном, по моему опыту. Если вы разложите класс, который решает какую-либо сложную проблему, создав вспомогательные классы, созданные из этого класса, вы можете воспользоваться возможностью безопасного передачи определенных данных этим дочерним объектам и в то же время скрывать их от кода клиента (который при условии, что все данные используются в операции высокого уровня). Предоставление таких вспомогательных классов в публичном API нарушает принцип скрытия информации, прерывания инкапсуляции и повышения сложности клиентского кода.
Избегание DI приводит к объектам без гражданства, которые действительно должны быть сдержанными, поскольку они почти всегда будут работать с данными, характерными для бизнес-операции.
Это относится не только к непубличным вспомогательным классам, но также к общедоступным классам "бизнес-услуг", вызываемым из объектов интерфейса/представления. Такие классы обслуживания обычно являются внутренним кодом (для одного бизнес-приложения), который по своей сути не используется повторно и имеет только несколько клиентов (часто только один), потому что такой код по своей природе относится к конкретному домену/случаю использования.
В этом случае (кстати, очень распространенный) гораздо разумнее, чтобы класс UI непосредственно создавал экземпляр класса бизнес-сервиса, передавая данные, предоставленные пользователем через конструктор.
Возможность легко писать модульные тесты для кода, как это, именно то, что привело меня к созданию инструментария JMockit. Я не думал о устаревшем коде, а о простоте и экономии дизайна. Результаты, достигнутые мной до сих пор, убедили меня в том, что тестируемость действительно является функцией двух переменных: ремонтопригодностью производственного кода и ограничениями издевательского инструмента, используемого для проверки этого кода. Итак, если вы удалите все ограничения от насмешливого инструмента, что вы получаете?
Ответ 3
Я полностью согласен с тем, что Testability не является конечной целью, это было одной из вещей, которые я понял при разработке PowerMock. Я также согласен с тем, что единичные тесты являются одним из способов получения хорошего дизайна. Использование PowerMock должно быть скорее исключение, чем правило, по крайней мере такие функции, как ожидания для конструкторов и статическое издевательство.
Основная мотивация, которую мы имеем для использования PowerMock, - это использование стороннего кода, который предотвращает проверку вашего кода. Хорошей альтернативой является антикоррупционный слой, который абстрагирует сторонний код и делает его доступным для тестирования. Однако иногда я думаю, что код чище, просто используя стандартные API. Хорошим примером этого является Java ME API. Это полон вызовов статических методов, которые предотвращают модульное тестирование.
Та же проблема может возникнуть и с устаревшим кодом. Некоторые организации очень боятся изменять свой существующий код, и в этом случае PowerMock может использоваться для внедрения модульного тестирования в тех частях, которые вы пишете в настоящий момент, не вызывая больших рефакторингов.
Наша проблема заключается в определении набора правил лучшей практики, когда использовать PowerMock или нет, что разработчик новичков может следовать. Создание хорошего дизайна действительно сложно, и поскольку PowerMock предоставляет вам больше возможностей, может быть, это становится сложнее для новичка? Я думаю, что более опытный разработчик ценит больше выбора.
(основатель PowerMock)
Ответ 4
Я думаю, что вы правы - если вам нужен PowerMock, у вас, вероятно, есть вонючий код. Избавьтесь от этой статики.
Однако, я думаю, вы ошибаетесь в отношении инструментария байт-кода. Я все время издеваюсь над конкретными классами, используя mockito - мне не нужно писать интерфейс для каждого. Один. класс. Это намного чище.
Только вы можете предотвратить запах кода.
Ответ 5
У нас было много одинаковых вопросов на арене .NET, в отношении Typemock Isolator.
См. Это сообщение в блоге
Я думаю, что когда люди начинают понимать, что Testability не является конечной целью, и этот дизайн изучается другими способами, мы перестанем позволять нашему страху диктовать, какие инструменты мы используем, или не использовать более совершенную технологию, когда и если это становится актуальным.
Кроме того, имеет смысл выбрать способ проектирования, основанный на потребностях приложения. не позволяйте инструменту рассказать вам, как проектировать - это не даст вам выбора.
(я работаю в Typemock, но когда-то был против него)
Ответ 6
Слой абстракции, который Powermock обеспечивает над отражением, кажется привлекательным, но делает тесты хрупкими. Более конкретно:
- Отражение основывается на строковых именах методов/полей и т.д. Любое переименование нарушало бы тесты, а затем фиксировало бы все тесты, получающие доступ к этому методу путем отражения. По сравнению с тестом, который не требует отражения, все переименования будут реорганизованы в среду IDE.
-
Возможности Powermock stubbing new
, вызовы статических методов и т.д. заставляют вас заглянуть в детали реализации функции. Тесты должны в идеале проверять функциональность, например.
functionOldImplementation(){
List l = new ArrayList();
}
// old implementation changed to new
functionNewImplementation(){
List l = new LinkedList();
}
Отказывание вызова new ArrayList()
приведет к поломке тестов для вышеупомянутого рефакторинга. Тесты необходимы больше всего для выполнения регрессий, и они терпят неудачу, если это делается.
Недавно наткнулся на это article, он обращается к большинству вопросов, заданных в вопросе, думал, что я поделюсь им.
Некоторые ключевые моменты статьи:
-
Потребовалось 1,5 года, чтобы PowerMock + Javaassist совместим с
Java7 с момента его появления. Вот заметка из журнала изменений PowerMock:
Change log 1.5 (2012-12-04)
---------------------------
Upgraded to Javassist 3.17.1-GA, this means that PowerMock works in Java 7!
-
Сайт PowerMock говорит:
"Обратите внимание, что PowerMock в основном предназначен для людей с экспертами знания в модульном тестировании. Ввод его в руки младшего разработчики могут принести больше вреда, чем пользы".