Сравнение Mockito и JMockit - почему за Mockito проголосовали лучше, чем за JMockit? [закрыто]

124

Я изучаю, какой фреймворк использовать для моего проекта, и сузил его до JMockit и Mockito .

Я заметил, что Mockito был признан " лучшим фреймворком для Java " на Stackoverflow.
При сравнении функций « Матрицы сравнения инструментов Mocking Tool » JMockit кажется, что JMockit имеет несколько различных функций.

Есть ли у кого-нибудь конкретная информация (а не мнения) о том, что может делать Mockito , чего нельзя достичь с помощью JMockit и наоборот?

Рожерио
источник
2
возможно, лучшее юзабилити для mockito, кстати, я не думаю, что JMockit более зрелый, чем Mockito ...
Алоис Кочард
42
Судя по количеству голосов, ОЗНАКО, что ответы на этот вопрос очень востребованы сообществом. Это означает, что стратегия ортогонализации этого сайта, которая привела к закрытию этого вопроса, требует серьезного переосмысления - в том смысле, что этот сайт часто наступал на ноги, чтобы дать необходимые ответы, упав на свою несовпадающую ортогональность. Не осознавая, что в граф-анализе дерева существует столько способов увидеть ортогональность дерева, сколько узлов. Возможно, нарушена ортогональность этого сайта, а не вопрос.
Blessed Geek
9
+1 за то, что не закрыл. Эти ответы имеют большую ценность. Выбрать технологию непросто, и ответы на эти вопросы помогут сэкономить много времени. На самом деле, может быть и нет правильного ответа, но StackOverflow должен отвечать на вопросы без ответа.
mhstnsc
6
Я добавлю свою поддержку тем, кто заявляет, что закрывать это как «неконструктивное» нелепо. Приведенные здесь ответы были подтверждены «фактами, ссылками и / или опытом». Вопрос в области технологий, который не требует каких-либо «дебатов, опросов или расширенного обсуждения», обычно не стоит задавать. Кроме того, предоставление фактов и опыта основывается на разном опыте, и эти различия приведут к дебатам и расширенным обсуждениям.
Джефф Найман
@Alois - вы можете привести конкретные примеры, когда JMockit выглядит менее зрелым, чем Mockito?
NitinS

Ответы:

140

Обновление, сентябрь 2019 г .: Единственный фреймворк для фиксации, поддерживаемый (по умолчанию) Spring Boot, - это Mockito . Если вы используете Spring, ответ очевиден.


Я бы сказал, что конкуренция идет между JMockit и PowerMock , затем Mockito .

Я бы оставил "простые" jMock и EasyMock, потому что они используют только прокси и CGLIB и не используют инструменты Java 5, как более новые фреймворки.

У jMock также не было стабильной версии более 4 лет. jMock 2.6.0 потребовалось 2 года для перехода от RC1 к RC2, а затем еще 2 года, прежде чем он был выпущен.

Что касается прокси и CGLIB по сравнению с инструментарием:

(EasyMock и jMock) основаны на java.lang.reflect.Proxy, который требует реализации интерфейса. Кроме того, они поддерживают создание фиктивных объектов для классов посредством генерации подклассов CGLIB. Из-за этого указанные классы не могут быть окончательными, и можно смоделировать только переопределяемые методы экземпляра. Однако наиболее важно то, что при использовании этих инструментов зависимости тестируемого кода (то есть объекты других классов, от которых зависит данный тестируемый класс) должны контролироваться тестами, чтобы фиктивные экземпляры могли передаваться клиентам. этих зависимостей. Следовательно, зависимости не могут быть просто созданы с помощью нового оператора в клиентском классе, для которого мы хотим написать модульные тесты.

В конечном счете, технические ограничения обычных средств имитации накладывают следующие ограничения на дизайн производственного кода:

  1. Каждый класс, который может потребоваться имитировать в тесте, должен либо реализовывать отдельный интерфейс, либо не быть окончательным.
  2. Зависимости каждого тестируемого класса должны быть либо получены с помощью настраиваемых методов создания экземпляров (фабрики или локатор служб), либо быть предоставлены для внедрения зависимостей. В противном случае модульные тесты не смогут передавать имитационные реализации зависимостей в тестируемый модуль.
  3. Поскольку имитировать можно только методы экземпляра, классы, подлежащие модульному тестированию, не могут вызывать какие-либо статические методы для своих зависимостей или создавать их экземпляры с помощью любого из конструкторов.

Вышеупомянутое скопировано с http://jmockit.org/about.html . Кроме того, он сравнивает себя (JMockit), PowerMock и Mockito несколькими способами:

Теперь существуют другие инструменты для имитации Java, которые также преодолевают ограничения обычных инструментов, среди которых PowerMock, jEasyTest и MockInject. Наиболее близким к набору функций JMockit является PowerMock, поэтому я кратко оценим его здесь (кроме того, два других более ограничены и, похоже, больше не разрабатываются активно).

JMockit против PowerMock

  • Прежде всего, PowerMock не предоставляет полного API для имитации, а вместо этого работает как расширение другого инструмента, которым в настоящее время может быть EasyMock или Mockito. Очевидно, что это преимущество для существующих пользователей этих инструментов.
  • JMockit, с другой стороны, предоставляет совершенно новые API, хотя его основной API (Expectations) похож как на EasyMock, так и на jMock. Хотя это создает более длительную кривую обучения, это также позволяет JMockit предоставлять более простой, согласованный и легкий в использовании API.
  • По сравнению с JMockit Expectations API, PowerMock API является более «низкоуровневым», заставляя пользователей выяснять и указывать, какие классы необходимо подготовить для тестирования (с аннотацией @PrepareForTest ({ClassA.class, ...}) ) и требуя определенных вызовов API для работы с различными типами языковых конструкций, которые могут присутствовать в производственном коде: статические методы (mockStatic (ClassA.class)), конструкторы (подавить (constructor (ClassXyz.class))), вызовы конструкторов ( expectNew (AClass.class)), частичные имитации (createPartialMock (ClassX.class, «methodToMock»)) и т. д.
  • С JMockit Expectations все виды методов и конструкторов имитируются чисто декларативным способом, с частичным имитированием, указанным с помощью регулярных выражений в аннотации @Mocked, или просто «демокингом» членов без зафиксированных ожиданий; то есть разработчик просто объявляет некоторые общие «фиктивные поля» для тестового класса или некоторые «локальные фиктивные поля» и / или «фиктивные параметры» для отдельных методов тестирования (и в этом последнем случае аннотация @Mocked часто не быть нужным).
  • Некоторые возможности, доступные в JMockit, такие как поддержка имитации равенства и hashCode, переопределенных методов и другие, в настоящее время не поддерживаются в PowerMock. Кроме того, нет эквивалента способности JMockit захватывать экземпляры и имитировать реализации указанных базовых типов во время выполнения теста, при этом сам тестовый код не знает реальных классов реализации.
  • PowerMock использует пользовательские загрузчики классов (обычно по одному на каждый тестовый класс) для создания модифицированных версий имитируемых классов. Такое интенсивное использование пользовательских загрузчиков классов может привести к конфликтам со сторонними библиотеками, поэтому иногда возникает необходимость использовать аннотацию @PowerMockIgnore («package.to.be.ignored») в тестовых классах.
  • Механизм, используемый JMockit (инструментирование времени выполнения с помощью «агента Java»), проще и безопаснее, хотя он требует передачи параметра «-javaagent» в JVM при разработке на JDK 1.5; в JDK 1.6+ (который всегда можно использовать для разработки, даже при развертывании в более старой версии) такого требования нет, поскольку JMockit может прозрачно загружать агент Java по запросу с помощью Attach API.

Еще один недавний инструмент издевательства - Mockito. Хотя он не пытается преодолеть ограничения старых инструментов (jMock, EasyMock), он вводит новый стиль тестирования поведения с помощью имитаций. JMockit также поддерживает этот альтернативный стиль через API проверки.

JMockit против Mockito

  • Mockito полагается на явные вызовы своего API, чтобы разделить код между этапами записи (когда (...)) и проверки (проверка (...)). Это означает, что любой вызов фиктивного объекта в тестовом коде также потребует вызова фиктивного API. Кроме того, это часто приводит к повторяющимся вызовам when (...) и verify (mock) ....
  • В JMockit подобных вызовов не существует. Конечно, у нас есть вызовы конструкторов new NonStrictExpectations () и new Verifications (), но они происходят только один раз за тест (обычно) и полностью отделены от вызовов имитируемых методов и конструкторов.
  • API Mockito содержит несколько несоответствий в синтаксисе, используемом для вызовов имитируемых методов. На этапе записи у нас есть такие вызовы, как when (mock.mockedMethod (args)) ... в то время как на этапе проверки этот же вызов будет записан как verify (mock) .mockedMethod (args). Обратите внимание, что в первом случае вызов mockedMethod выполняется непосредственно для фиктивного объекта, а во втором случае - для объекта, возвращаемого функцией verify (mock).
  • JMockit не имеет таких несоответствий, потому что вызовы имитированных методов всегда выполняются непосредственно на самих имитируемых экземплярах. (Только за одним исключением: для сопоставления вызовов одного и того же имитируемого экземпляра используется вызов onInstance (mock), в результате чего получается такой код, как onInstance (mock) .mockedMethod (args); однако в большинстве тестов это не требуется. )
  • Как и другие имитирующие инструменты, которые полагаются на цепочку / упаковку методов, Mockito также сталкивается с противоречивым синтаксисом при замене методов void. Например, вы пишете when (mockedList.get (1)). ThenThrow (new RuntimeException ()); для непустого метода и doThrow (new RuntimeException ()). when (mockedList) .clear (); за пустую. В JMockit всегда один и тот же синтаксис: mockedList.clear (); result = new RuntimeException () ;.
  • Еще одно несоответствие возникает при использовании шпионов Mockito: «имитируют», которые позволяют выполнять реальные методы на шпионском экземпляре. Например, если шпион ссылается на пустой список, то вместо записи when (spy.get (0)). ThenReturn ("foo") вам нужно будет написать doReturn ("foo"). When (spy) .get ( 0). В JMockit функция динамического имитации обеспечивает аналогичные функции для шпионов, но без этой проблемы, поскольку реальные методы выполняются только во время фазы воспроизведения.
  • В EasyMock и jMock, первых имитирующих API для Java, основное внимание уделялось записи ожидаемых вызовов имитируемых методов для фиктивных объектов, которые (по умолчанию) не допускают неожиданных вызовов. Эти API-интерфейсы также обеспечивают запись разрешенных вызовов для фиктивных объектов, которые допускают неожиданные вызовы, но это рассматривалось как функция второго сорта. Кроме того, с этими инструментами нет возможности явно проверить вызовы имитаций после выполнения тестируемого кода. Все такие проверки выполняются неявно и автоматически.
  • В Mockito (а также в Unitils Mock) используется противоположная точка зрения. Все вызовы имитирующих объектов, которые могут произойти во время теста, независимо от того, записаны они или нет, разрешены и никогда не ожидаются. Проверка выполняется явно после выполнения тестируемого кода, а не автоматически.
  • Оба подхода слишком экстремальны и, следовательно, менее чем оптимальны. JMockit Expectations & Verifications - единственный API, который позволяет разработчику легко выбирать лучшую комбинацию строгих (ожидаемых по умолчанию) и нестрогих (разрешенных по умолчанию) имитационных вызовов для каждого теста.
  • Чтобы быть более понятным, API Mockito имеет следующий недостаток. Если вам нужно убедиться, что во время теста произошел вызов непустого имитационного метода, но для теста требуется возвращаемое значение из этого метода, которое отличается от значения по умолчанию для возвращаемого типа, тогда тест Mockito будет иметь повторяющийся код: вызов when (mock.someMethod ()). thenReturn (xyz) в фазе записи и verify (mock) .someMethod () в фазе проверки. С JMockit всегда можно записать строгое ожидание, которое не нужно явно проверять. В качестве альтернативы, ограничение количества вызовов (раз = 1) может быть указано для любого записанного нестрогого ожидания (с Mockito такие ограничения могут быть указаны только в вызове verify (mock, constraint)).
  • У Mockito плохой синтаксис для проверок по порядку и для полных проверок (то есть проверка того, что все вызовы имитирующих объектов явно проверены). В первом случае необходимо создать дополнительный объект и выполнить для него вызовы проверки: InOrder inOrder = inOrder (mock1, mock2, ...). Во втором случае необходимо выполнить такие вызовы, как verifyNoMoreInteractions (mock) или verifyZeroInteractions (mock1, mock2).
  • Используя JMockit, вы просто пишете new VerificationsInOrder () или new FullVerifications () вместо new Verification () (или new FullVerificationsInOrder () для объединения обоих требований). Не нужно указывать, какие макеты задействованы. Никаких лишних имитирующих вызовов API. И в качестве бонуса, вызывая unverifiedInvocations () внутри упорядоченного блока проверки, вы можете выполнять проверки, связанные с заказом, что просто невозможно в Mockito.

Наконец, JMockit Testing Toolkit имеет более широкую область применения и более амбициозные цели, чем другие наборы инструментов для имитации, чтобы предоставить полное и сложное решение для тестирования разработчиков. Хорошего API для имитации, даже без искусственных ограничений, недостаточно для продуктивного создания тестов. Независимый от IDE, простой в использовании и хорошо интегрированный инструмент Code Coverage также важен, и это то, что JMockit Coverage стремится обеспечить. Еще одна часть набора инструментов для тестирования разработчика, которая станет более полезной по мере увеличения размера набора тестов, - это возможность постепенно повторно запускать тесты после локализованного изменения производственного кода; это также включено в инструмент покрытия.

(конечно, источник может быть предвзятым, но что ж ...)

Я бы посоветовал пойти с JMockit . Это самый простой в использовании, гибкий и работает практически во всех случаях, даже в сложных и сценариях, когда вы не можете контролировать тестируемый класс (или вы не можете его сломать из-за соображений совместимости и т. Д.).

Мой опыт работы с JMockit был очень положительным.

Хенди Ираван
источник
1
Я никогда не использовал jmockit, но хотел бы добавить к обсуждению еще один аргумент: взгляните на сравнение тенденций Google всех обсуждаемых фреймворков. По состоянию на 06.06.2012 JMockit даже не отображается на графике тенденций Google по сравнению с Mockito и EasyMock. И количество пользователей также важно при выборе фреймворка.
техника
3
Это довольно странно. Mockito и JMockIt дают мне 409 'и 83' попаданий в Google соответственно. Конечно, JMockIt должен хотя бы появиться.
thoredge
5
Ваш ответ очень полезен. Я планировал просто использовать Mockito, но сейчас я сначала протестирую JMockit. Звучит неплохо, чтобы не пробовать. @machinery: Да, важно смотреть на тенденции, но выбор его в качестве основного критерия ограничит вас основным потоком и защитит вас от инноваций.
deamon
1
Я знаю, что это старая ветка, но после прочтения этого обзора я подумал, что тоже попробую. Я должен сказать, что на первый взгляд JMockit очень многообещающий. Однако на сегодняшний день я обнаружил, что поддержка этого сообщества очень недостаточна. У меня возникла большая проблема с моим пониманием Mock API, и после публикации моих вопросов я не получил ответа в течение 2 дней.
Эрик Б.
1
Ответу 8 лет, поэтому многие вещи в ответе неверны. Во-первых, JMockit требует -javaagentфлага с версии 1.42, потому что вы больше не можете самостоятельно подключаться, начиная с Java 9, и поиск подходящих обходных путей, очевидно, не входил в компетенцию разработчика. Другой момент заключается в том, что JMockit больше не позволяет имитировать частные методы и конструкторы, в то время как PowerMock делает afaik.
Вампир
24

Я работал как с Mockito, так и с JMockit, и мой опыт работы с ними:

  • Mockito:

    • неявное издевательство (-> удобство использования, но есть опасность не обнаруживать недопустимые вызовы методов на имитаторах)
    • явная проверка
  • EasyMock:

    • явное издевательство
    • неявная проверка
  • JMockit:

    • поддерживает оба
  • Кроме того, другие преимущества JMockit:

    • если вы имитируете статические методы / конструкторы и т. д. (например, расширяете очень старую устаревшую базу кода без UT), у вас будет два варианта: 1) Mockito / EasyMock с расширением Powermock или 2) Jmockit
    • встроенный отчет о покрытии

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

Tümer
источник
есть stackoverflow.com/questions/8003278/… "verifyNoMoreInteractions" Я полагаю, если вы хотите псевдо-явное издевательство с mockito
rogerdpack
15

Я использую jMockit только потому, что он содержит библиотеки отражения в Deencapsultation.class. Мне действительно нравится стиль Mockito, но я отказываюсь менять свой код и запутывать свой API только для того, чтобы ограниченная среда тестирования могла это сделать. И я фанат тестирования всего своего кода, поэтому фреймворк, который не может легко тестировать частные методы, - это не то, что я хочу использовать.

Я был потрясен этой статьей

После (по общему признанию большой) кривой обучения jMockit теперь является моей основной средой модульного тестирования для моков.

Джозеф Эриксон
источник
7
Возможно, если вы чувствуете, что вам нужно протестировать частные методы, вас слишком заботит то, как работает ваш код, а не то, что он делает (что является реальным моментом, и что можно определить, используя только его общедоступные методы). Также мне было бы интересно прочитать эту статью, но ссылка не работает.
codebox
Спустя 4 года вы все еще используете jMockit в качестве основной среды тестирования? Я пробую его в первый раз и сталкиваюсь с несколькими проблемами, но я не знаю, неправильно ли я понимаю, как работает jMockit, или это функция, которой просто не существует.
Эрик Б.
jMockit больше не поддерживает тестирование частных методов. Класс Deencapsulation постепенно устарел, а затем полностью был удален в версии 1.47. jmockit.github.io/changes.html
Pytry
4

Для легкого тестирования нашей устаревшей кодовой базы (с большим количеством вызовов статических методов и т. Д.) JMockit оказался бесценным. [Бесстыдный плагин для статьи в моем блоге]

Джефф Олсон
источник
0

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

Bivas
источник