web-dev-qa-db-fra.com

Comparaison entre Mockito et JMockit - Pourquoi Mockito est-il mieux élu que JMockit?

Je cherche quel cadre moqueur utiliser pour mon projet et je l'ai réduit à JMockit et Mockito .

Je remarque que Mockito a été voté " le meilleur framework fictif pour Java " sur Stackoverflow.
En comparant les caractéristiques sur de JMockit " matrice de comparaison d’outil moqueur ", il apparaît que JMockit présente de nombreuses fonctionnalités différentes.

Est-ce que quelqu'un a des informations spécifiques (pas des opinions) sur ce que Mockito peut faire et que l'on ne peut pas obtenir avec JMockit et vice versa?

118
user63904

Je dirais que la concurrence est entre JMockit et PowerMock , puis Mockito .

Je laisserais "plain" jMock et EasyMock car ils utilisent uniquement proxy & CGLIB et n'utilisent pas d'instrumentation Java 5 comme les nouveaux frameworks.

jMock n'a pas non plus de version stable depuis plus de 4 ans. Il a fallu 2 ans à jMock 2.6.0 pour passer de RC1 à RC2, puis 2 autres années avant la sortie effective.

Concernant Proxy & CGLIB vs instrumentation:

(EasyMock et jMock) reposent sur Java.lang.reflect.Proxy, qui nécessite la mise en œuvre d’une interface. De plus, ils prennent en charge la création d'objets fictifs pour les classes via la génération de sous-classes CGLIB. De ce fait, lesdites classes ne peuvent pas être définitives et seules les méthodes d'instance pouvant être remplacées peuvent être simulées. Plus important encore, lors de l'utilisation de ces outils, les dépendances du code sous test (c'est-à-dire les objets d'autres classes dont dépend une classe sous test donnée) doivent être contrôlées par les tests, afin que des instances fictives puissent être transmises aux clients. de ces dépendances. Par conséquent, les dépendances ne peuvent pas simplement être instanciées avec le nouvel opérateur dans une classe client pour laquelle nous voulons écrire des tests unitaires.

En fin de compte, les limitations techniques des outils de moquage classiques imposent les codes de conception suivants au code de production:

  1. Chaque classe devant éventuellement être simulée dans un test doit implémenter une interface distincte ou ne pas être finale.
  2. Les dépendances de chaque classe à tester doivent soit être obtenues à l'aide de méthodes de création d'instances configurables (usines ou un localisateur de service), soit être exposées à l'injection de dépendances. Sinon, les tests unitaires ne pourront pas transmettre les implémentations factices de dépendances à l'unité testée.
  3. Etant donné que seules les méthodes d'instance peuvent être simulées, les classes à tester d'unité ne peuvent appeler aucune méthode statique sur leurs dépendances, ni les instancier avec un constructeur.

Ce qui précède est copié de http://jmockit.org/about.html . En outre, il se compare (JMockit), PowerMock et Mockito de plusieurs manières:

Il existe maintenant d’autres outils moqueurs pour Java qui surmontent également les limites des outils classiques, entre eux, PowerMock, jEasyTest et MockInject. Celui qui se rapproche le plus des fonctionnalités de JMockit est PowerMock, je vais donc l'évaluer brièvement ici (en plus, les deux autres sont plus limités et ne semblent plus être activement développés).

JMockit vs PowerMock

  • Tout d’abord, PowerMock ne fournit pas une API complète pour le moquage, mais fonctionne plutôt comme une extension d’un autre outil, qui peut actuellement être EasyMock ou Mockito. Ceci est évidemment un avantage pour les utilisateurs existants de ces outils.
  • JMockit, en revanche, fournit des API entièrement nouvelles, bien que son API principale (Expectations) soit similaire à EasyMock et à jMock. Bien que cela crée une courbe d'apprentissage plus longue, cela permet également à JMockit de fournir une API plus simple, plus cohérente et plus facile à utiliser.
  • Comparée à l'API JMockit Expectations, l'API PowerMock est plus "bas niveau", forçant les utilisateurs à déterminer et à spécifier les classes devant être préparées pour les tests (avec l'annotation @PrepareForTest ({ClassA.class, ...}) ) et nécessitant des appels d'API spécifiques pour traiter divers types de constructions de langage pouvant être présents dans le code de production: méthodes statiques (mockStatic (ClassA.class)), constructeurs (suppress (constructeur (ClassXyz.class))), invocations de constructeurs ( expectNew (AClass.class)), mocks partiels (createPartialMock (ClassX.class, "methodToMock")), etc.
  • Avec JMockit Expectations, toutes sortes de méthodes et de constructeurs sont simulés de manière purement déclarative, avec un raillage partiel spécifié à l'aide d'expressions régulières dans l'annotation @Mocked ou simplement en "dé-moquant" les membres sans attentes enregistrées. c'est-à-dire que le développeur déclare simplement des "champs fictifs" partagés pour la classe de test, ou des "champs fictifs locaux" et/ou des "paramètres fictifs" pour des méthodes de test individuelles (et dans ce dernier cas, l'annotation @Mocked ne le sera souvent pas. être nécessaire).
  • Certaines fonctionnalités disponibles dans JMockit, telles que la prise en charge de mocking equals et de hashCode, les méthodes remplacées et autres, ne sont actuellement pas prises en charge dans PowerMock. En outre, la capacité de JMockit à capturer des instances et des implémentations factices de types de base spécifiés pendant l'exécution du test est sans équivalent, sans que le code de test lui-même ne connaisse les classes d'implémentation réelles.
  • PowerMock utilise des chargeurs de classes personnalisés (généralement un par classe de test) afin de générer des versions modifiées des classes simulées. Une telle utilisation intensive de chargeurs de classes personnalisés peut entraîner des conflits avec des bibliothèques tierces, d'où la nécessité d'utiliser parfois l'annotation @PowerMockIgnore ("package.to.be.ignored") sur les classes de test.
  • Le mécanisme utilisé par JMockit (instrumentation d'exécution via un "agent Java") est plus simple et plus sûr, bien qu'il nécessite la transmission d'un paramètre "-javaagent" à la JVM lors du développement sur JDK 1.5; sur JDK 1.6+ (qui peut toujours être utilisé pour le développement, même en cas de déploiement sur une version antérieure), cette exigence n’existe pas, car JMockit peut charger de manière transparente l’agent Java à la demande) à l’aide de Attach API.

Mockito est un autre outil moqueur récent. Bien qu'il ne tente pas de surmonter les limitations des outils plus anciens (jMock, EasyMock), il introduit un nouveau style de test de comportement avec mock. JMockit prend également en charge ce style alternatif via l'API de vérification.

JMockit vs Mockito

  • Mockito s'appuie sur des appels explicites à son API afin de séparer le code entre les phases de l'enregistrement (quand (...)) et de la vérification (vérifier (...)). Cela signifie que tout appel à un objet factice dans le code de test nécessitera également un appel à l'API émettrice. De plus, cela entraîne souvent des appels répétitifs lorsque (...) et vérifie (simulacre) ... des appels.
  • Avec JMockit, aucun appel similaire n'existe. Bien sûr, nous avons les nouveaux appels de constructeur NonStrictExpectations () et Verifications (), mais ils ne se produisent qu’une fois par test (en général) et sont complètement distincts des invocations aux méthodes et constructeurs simulés.
  • L'API Mockito contient plusieurs incohérences dans la syntaxe utilisée pour les appels aux méthodes simulées. Dans la phase d'enregistrement, nous avons des appels tels que when (mock.mockedMethod (args)) ... tandis que dans la phase de vérification, ce même appel est écrit comme verify (mock) .mockedMethod (args). Notez que dans le premier cas, l'appel à mockedMethod est effectué directement sur l'objet fictif, tandis que dans le second cas, il est fait sur l'objet renvoyé par verify (mock).
  • JMockit n'a pas de telles incohérences car les invocations aux méthodes simulées sont toujours effectuées directement sur les instances simulées elles-mêmes. (À une exception près: pour faire correspondre les invocations à la même instance fictive, un appel onInstance (fictif) est utilisé, ce qui donne un code semblable à onInstance (fictif) .mockedMethod (args); la plupart des tests ne l'utiliseront toutefois pas. )
  • Tout comme les autres outils de moquage qui reposent sur l’enchaînement/l’enveloppement de méthodes, Mockito utilise également une syntaxe incohérente lorsqu’on réduit les méthodes void. Par exemple, vous écrivez quand (mockedList.get (1)). ThenThrow (new RuntimeException ()); pour une méthode non vide, et doThrow (new RuntimeException ()). when (mockedList) .clear (); pour un vide. Avec JMockit, c'est toujours la même syntaxe: mockedList.clear (); result = new RuntimeException () ;.
  • Une autre incohérence se produit dans l'utilisation des espions Mockito: les "moqueurs" qui permettent aux méthodes réelles d'être exécutées sur l'instance espionnée. Par exemple, si espion fait référence à une liste vide, alors, au lieu d'écrire quand (spy.get (0)). ThenReturn ("foo"), vous devrez écrire doReturn ("foo"). When (spy) .get ( 0) Avec JMockit, la fonctionnalité de moquage dynamique fournit des fonctionnalités similaires à celles des espions, mais sans ce problème, car les méthodes réelles ne sont exécutées que pendant la phase de relecture.
  • Dans EasyMock et jMock, les premières API mocking pour Java, l’accent était entièrement mis sur l’enregistrement des invocations attendues des méthodes simulées, pour les objets fictifs qui (par défaut) ne permettent pas d’appels inattendus. Ces API fournissent également l'enregistrement des invocations autorisées pour les objets fictifs qui permettent des invocations inattendues, mais cela a été traité comme une fonctionnalité de seconde classe. De plus, avec ces outils, il n'y a aucun moyen de vérifier explicitement les invocations après le code testé. Toutes ces vérifications sont effectuées implicitement et automatiquement.
  • Dans Mockito (et aussi dans Unitils Mock), le point de vue opposé est pris. Tous les appels à simuler des objets pouvant survenir pendant le test, qu'ils soient enregistrés ou non, sont autorisés, jamais prévus. La vérification est effectuée explicitement après l'exercice du code sous test, jamais automatiquement.
  • Les deux approches sont trop extrêmes et, par conséquent, moins qu'optimales. JMockit Expectations & Verifications est la seule API permettant au développeur de choisir en toute transparence la meilleure combinaison d'appels factices fictifs strict (attendu par défaut) et non stricte (autorisé par défaut) pour chaque test.
  • Pour être plus clair, l’API Mockito présente les inconvénients suivants. Si vous devez vérifier qu'un appel à une méthode non void mocked a eu lieu pendant le test, mais que le test requiert une valeur de retour de cette méthode différente de la valeur par défaut pour le type de retour, le test Mockito comportera un code en double: un appel when (mock.someMethod ()). thenReturn (xyz) dans la phase d'enregistrement et un mock (mock) .someMethod () dans la phase de vérification. Avec JMockit, une attente stricte peut toujours être enregistrée, ce qui ne nécessite pas de vérification explicite. Alternativement, une contrainte de nombre d'appels (times = 1) peut être spécifiée pour toute attente non stricte enregistrée (avec Mockito, de telles contraintes ne peuvent être spécifiées que dans un appel verify (mock, constraint)).
  • Mockito a une syntaxe médiocre pour les vérifications dans l’ordre et pour les vérifications complètes (c’est-à-dire que toutes les invocations d’objets fictifs sont vérifiées explicitement). Dans le premier cas, un objet supplémentaire doit être créé et des appels à vérifier sont effectués: InOrder inOrder = inOrder (mock1, mock2, ...). Dans le second cas, des appels tels que verifyNoMoreInteractions (mock) ou verifyZeroInteractions (mock1, mock2) doivent être effectués.
  • Avec JMockit, vous écrivez simplement un nouveau VerificationsInOrder () ou un nouveau FullVerifications () au lieu de nouveau Verifications () (ou du nouveau FullVerificationsInOrder () pour combiner les deux exigences). Pas besoin de spécifier quels objets fictifs sont impliqués. Aucun appel d'API moqueur supplémentaire. Et en prime, en appelant unverifiedInvocations () à l'intérieur d'un bloc de vérification commandé, vous pouvez effectuer des vérifications liées à la commande qui sont tout simplement impossibles dans Mockito.

Enfin, la boîte à outils de test JMockit a une portée plus large et des objectifs plus ambitieux que les autres kits de simulation, afin de fournir une solution complète et sophistiquée de testeur. Une bonne API pour se moquer, même sans limitations artificielles, ne suffit pas pour une création productive de tests. Un outil IDE agnostique, facile à utiliser et bien intégré est également essentiel, et c'est ce que JMockit Coverage vise à fournir. Un autre élément du jeu d'outils de test pour les développeurs qui deviendra plus utile à mesure que la suite de tests s'agrandit est la possibilité de réexécuter les tests de manière incrémentielle après une modification localisée du code de production; cela est également inclus dans l'outil Couverture.

(d'accord, la source peut être biaisée, mais bon ...)

Je dirais aller avec JMockit . C'est le plus facile à utiliser, flexible et fonctionne dans presque tous les cas, même les plus difficiles et les scénarios où vous ne pouvez pas contrôler la classe à tester (ou vous ne pouvez pas la casser pour des raisons de compatibilité, etc.).

Mes expériences avec JMockit ont été très positives.

136
Hendy Irawan

J'ai travaillé avec Mockito et JMockit, et mon expérience avec eux est:

  • Mockito:

    • moquage implicite (-> meilleure utilisation, mais risque de ne pas détecter les appels de méthode non autorisés sur les mock)
    • vérification explicite
  • EasyMock:

    • expliquer moqueur
    • vérification implicite
  • JMockit:

    • soutient les deux
  • En outre, d'autres avantages de JMockit:

    • si vous vous moquez de méthodes/constructeurs statiques, etc. (tels que l'extension d'une très ancienne base de code sans UT), vous aurez le choix entre deux possibilités: 1) Mockito/EasyMock avec extension Powermock ou 2) Jmockit
    • rapport de couverture intégré

Personnellement, je préfère JMockit, qui, à mon avis, est plus riche en fonctionnalités et flexible, mais nécessite une courbe d’apprentissage un peu plus raide. Il y a généralement plusieurs façons d'obtenir le même effet moqueur et nécessite plus de soin lors de la conception des simulacres.

23
Tumer

J'utilise jMockit seulement à cause de ses bibliothèques de réflexion dans Deencapsultation.class. J'adore le style de Mockito, mais je refuse de changer de code et de confondre mon API avec un framework de test limité. Et je suis un fan de tester tout mon code, donc un framework qui ne peut pas facilement tester des méthodes privées n'est pas ce que je veux utiliser.

J'ai été influencé par cet article

Après une courbe d'apprentissage (certes importante), jMockit est maintenant mon principal cadre de test unitaire pour les simulacres.

15
Joseph Erickson

Pour tester facilement notre base de code existante (avec de nombreux appels de méthodes statiques, etc.), JMockit a été inestimable. [Prise éhontée pour un article sur mon blog]

4
Jeff Olson

Personnellement, je préfère EasyMock .
La possibilité de passer d’un contrôle ludique normal à un contrôle strict est un élément de ma fonctionnalité préférée.

0
Bivas