Использование 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 в основном предназначен для людей с экспертами знания в модульном тестировании. Ввод его в руки младшего разработчики могут принести больше вреда, чем пользы".