Confronto tra Mockito e JMockit: perché Mockito è stato votato meglio di JMockit? [chiuso]


124

Sto indagando su quale framework beffardo utilizzare per il mio progetto e l'ho ristretto a JMockit e Mockito .

Ho notato che Mockito è stato votato " il miglior framework fittizio per Java " su Stackoverflow.
Confrontando le caratteristiche sulla " Matrice di confronto degli strumenti di simulazione " di JMockit , sembra che JMockit abbia molteplici caratteristiche differenti.

Qualcuno ha delle informazioni specifiche (non opinioni) su ciò che Mockito può fare che non può essere ottenuto con JMockit e viceversa?


2
forse una migliore usabilità per mockito, btw non credo che JMockit sia più maturo di Mockito ...
Alois Cochard

42
A giudicare dal numero di voti, OVVIAMENTE le risposte a questa domanda sono molto ricercate dalla comunità. Il che significa che la strategia di ortogonalizzazione di questo sito che ha causato la chiusura di questa domanda necessita di un serio ripensamento - in quanto questo sito si è spesso messo in piedi nel riuscire a fornire le risposte necessarie cadendo nella sua ortogonalità disallineata. Non rendendosi conto che nell'analisi del grafo di un albero ci sono tanti modi per visualizzare l'ortogonalità di un albero quanti sono i nodi. Forse l'ortogonalità di questo sito, piuttosto che quella della domanda, è disallineata.
Blessed Geek

9
+1 per non chiudere. Queste risposte hanno un valore enorme. Scegliere una tecnologia non è facile e queste domande possono far risparmiare molto tempo. In effetti potrebbe non esserci una risposta giusta, ma StackOverflow dovrebbe adattarsi alle domande senza una risposta.
mhstnsc

6
Aggiungerò il mio sostegno a coloro che affermano che chiudere questo come "non costruttivo" è ridicolo. Le risposte fornite qui sono state supportate da "fatti, riferimenti e / o competenze". Una domanda nel regno della tecnologia che non sollecita alcuni "dibattiti, sondaggi o discussioni estese" di solito vale a malapena la pena di essere posta. Inoltre, fornire fatti e competenze si basa su esperienze diverse e tali differenze porteranno al dibattito e alla discussione estesa.
Jeff Nyman

@Alois - puoi fornire esempi concreti in cui JMockit sembra meno maturo di Mockito?
NitinS

Risposte:


140

Aggiornamento settembre 2019: l'unico framework beffardo supportato (per impostazione predefinita) da Spring Boot è Mockito . Se usi Spring, la risposta è abbastanza ovvia.


Direi che la competizione è tra JMockit e PowerMock , poi Mockito .

Lascerei jMock ed EasyMock "semplici" perché usano solo proxy e CGLIB e non usano strumentazione Java 5 come i framework più recenti.

jMock inoltre non ha avuto una versione stabile per oltre 4 anni. jMock 2.6.0 ha richiesto 2 anni per passare da RC1 a RC2, e poi altri 2 anni prima che fosse effettivamente rilasciato.

Per quanto riguarda Proxy e CGLIB vs strumentazione:

(EasyMock e jMock) sono basati su java.lang.reflect.Proxy, che richiede l'implementazione di un'interfaccia. Inoltre, supportano la creazione di oggetti fittizi per le classi tramite la generazione di sottoclassi CGLIB. Per questo motivo, dette classi non possono essere finali e solo i metodi di istanza sovrascrivibili possono essere derisi. La cosa più importante, tuttavia, quando si utilizzano questi strumenti le dipendenze del codice sotto test (cioè, gli oggetti di altre classi da cui dipende una data classe sotto test) devono essere controllate dai test, in modo che le istanze fittizie possano essere passate ai client di quelle dipendenze. Pertanto, le dipendenze non possono essere semplicemente istanziate con il nuovo operatore in una classe client per la quale si desidera scrivere unit test.

In definitiva, i limiti tecnici degli strumenti di derisione convenzionali impongono le seguenti limitazioni di progettazione al codice di produzione:

  1. Ogni classe che potrebbe dover essere derisa in un test deve implementare un'interfaccia separata o non essere definitiva.
  2. Le dipendenze di ogni classe da testare devono essere ottenute tramite metodi di creazione di istanze configurabili (factory o un Service Locator) o essere esposte per l'inserimento delle dipendenze. In caso contrario, gli unit test non saranno in grado di passare implementazioni fittizie di dipendenze all'unità sottoposta a test.
  3. Poiché solo i metodi di istanza possono essere derisi, le classi da sottoporre a test unitario non possono chiamare alcun metodo statico sulle loro dipendenze, né istanziarle utilizzando uno dei costruttori.

Quanto sopra è stato copiato da http://jmockit.org/about.html . Inoltre, confronta se stesso (JMockit), PowerMock e Mockito in diversi modi:

Ora ci sono altri strumenti di derisione per Java che superano anche i limiti di quelli convenzionali, tra cui PowerMock, jEasyTest e MockInject. Quello che si avvicina di più al set di funzionalità di JMockit è PowerMock, quindi lo valuterò brevemente qui (inoltre, gli altri due sono più limitati e non sembrano più essere sviluppati attivamente).

JMockit contro PowerMock

  • Prima di tutto, PowerMock non fornisce un'API completa per il mocking, ma funziona invece come un'estensione di un altro strumento, che attualmente può essere EasyMock o Mockito. Questo è ovviamente un vantaggio per gli utenti esistenti di questi strumenti.
  • JMockit, d'altra parte, fornisce API completamente nuove, sebbene la sua API principale (Expectations) sia simile sia a EasyMock che a jMock. Sebbene ciò crei una curva di apprendimento più lunga, consente anche a JMockit di fornire un'API più semplice, più coerente e più facile da usare.
  • Rispetto all'API JMockit Expectations, l'API PowerMock è più "di basso livello", costringendo gli utenti a capire e specificare quali classi devono essere preparate per il test (con l'annotazione @PrepareForTest ({ClassA.class, ...}) ) e che richiedono chiamate API specifiche per gestire vari tipi di costrutti del linguaggio che possono essere presenti nel codice di produzione: metodi statici (mockStatic (ClassA.class)), costruttori (sopprimere (costruttore (ClassXyz.class))), invocazioni di costruttori ( waitNew (AClass.class)), mock parziali (createPartialMock (ClassX.class, "methodToMock")), ecc.
  • Con JMockit Expectations, tutti i tipi di metodi e costruttori vengono derisi in modo puramente dichiarativo, con derisione parziale specificata tramite espressioni regolari nell'annotazione @Mocked o semplicemente "un-mocking" dei membri senza aspettative registrate; cioè, lo sviluppatore dichiara semplicemente alcuni "campi fittizi" condivisi per la classe di test, o alcuni "campi fittizi locali" e / o "parametri fittizi" per i metodi di prova individuali (e in quest'ultimo caso l'annotazione @Mocked spesso non essere necessario).
  • Alcune funzionalità disponibili in JMockit, come il supporto per derisione di uguali e hashCode, metodi sostituiti e altri, non sono attualmente supportate in PowerMock. Inoltre, non esiste alcun equivalente alla capacità di JMockit di acquisire istanze e simulare implementazioni di tipi di base specificati durante l'esecuzione del test, senza che il codice del test stesso abbia alcuna conoscenza delle effettive classi di implementazione.
  • PowerMock utilizza caricatori di classi personalizzati (di solito uno per classe di test) per generare versioni modificate delle classi derise. Un uso così intenso di programmi di caricamento classi personalizzati può portare a conflitti con librerie di terze parti, da qui la necessità di utilizzare a volte l'annotazione @PowerMockIgnore ("package.to.be.ignored") sulle classi di test.
  • Il meccanismo utilizzato da JMockit (strumentazione runtime tramite un "agente Java") è più semplice e sicuro, sebbene richieda il passaggio di un parametro "-javaagent" alla JVM durante lo sviluppo su JDK 1.5; su JDK 1.6+ (che può essere sempre utilizzato per lo sviluppo, anche se distribuito su una versione precedente) non esiste tale requisito, poiché JMockit può caricare in modo trasparente l'agente Java su richiesta utilizzando l'API di collegamento.

Un altro strumento di derisione recente è Mockito. Sebbene non tenti di superare i limiti dei vecchi strumenti (jMock, EasyMock), introduce un nuovo stile di test del comportamento con i mock. JMockit supporta anche questo stile alternativo, tramite l'API Verifications.

JMockit contro Mockito

  • Mockito si basa su chiamate esplicite alla sua API per separare il codice tra le fasi di registrazione (quando (...)) e di verifica (verifica (...)). Ciò significa che qualsiasi invocazione a un oggetto fittizio nel codice di test richiederà anche una chiamata all'API fittizia. Inoltre, questo spesso porterà a chiamate ripetitive quando (...) e verificate (simulate) ....
  • Con JMockit, non esistono chiamate simili. Certo, abbiamo le nuove chiamate ai costruttori NonStrictExpectations () e Verifications (), ma si verificano solo una volta per test (in genere) e sono completamente separate dalle invocazioni a metodi e costruttori derisi.
  • L'API Mockito contiene diverse incongruenze nella sintassi utilizzata per le chiamate ai metodi derisi. Nella fase di registrazione, abbiamo chiamate come when (mock.mockedMethod (args)) ... mentre nella fase di verifica questa stessa chiamata verrà scritta come verify (mock) .mockedMethod (args). Si noti che nel primo caso l'invocazione a mockedMethod viene effettuata direttamente sull'oggetto mock, mentre nel secondo caso viene effettuata sull'oggetto restituito da verify (mock).
  • JMockit non presenta tali incongruenze perché le invocazioni ai metodi fittizi vengono sempre effettuate direttamente sulle istanze fittizie stesse. (Con una sola eccezione: per abbinare le invocazioni sulla stessa istanza derisa, viene utilizzata una chiamata onInstance (mock), risultando in codice come onInstance (mock) .mockedMethod (args); la maggior parte dei test non avrà bisogno di usarlo, però. )
  • Proprio come altri strumenti di derisione che si basano sul concatenamento / avvolgimento di metodi, Mockito si imbatte anche in una sintassi incoerente durante lo stubbing dei metodi void. Ad esempio, scrivi when (mockedList.get (1)). ThenThrow (new RuntimeException ()); per un metodo non void e doThrow (new RuntimeException ()). when (mockedList) .clear (); per uno vuoto. Con JMockit, è sempre la stessa sintassi: mockedList.clear (); risultato = new RuntimeException () ;.
  • Un'altra incongruenza si verifica nell'uso delle spie Mockito: "beffe" che consentono di eseguire i metodi reali sull'istanza spiata. Ad esempio, se spy fa riferimento a un elenco vuoto, invece di scrivere when (spy.get (0)). ThenReturn ("foo") dovrai scrivere doReturn ("foo"). When (spy) .get ( 0). Con JMockit, la funzionalità di mocking dinamico fornisce funzionalità simili alle spie, ma senza questo problema poiché i metodi reali vengono eseguiti solo durante la fase di riproduzione.
  • In EasyMock e jMock, le prime API mocking per Java, l'attenzione era interamente sulla registrazione di invocazioni attese di metodi mocked, per oggetti mock che (per impostazione predefinita) non consentono invocazioni impreviste. Tali API forniscono anche la registrazione delle chiamate consentite per oggetti fittizi che consentono chiamate impreviste, ma questa è stata considerata una funzionalità di seconda classe. Inoltre, con questi strumenti non c'è modo di verificare esplicitamente le invocazioni ai mock dopo che il codice sotto test è stato esercitato. Tutte queste verifiche vengono eseguite in modo implicito e automatico.
  • In Mockito (e anche in Unitils Mock), viene preso il punto di vista opposto. Tutte le invocazioni per falsificare oggetti che possono accadere durante il test, registrate o meno, sono consentite, mai previste. La verifica viene eseguita esplicitamente dopo aver esercitato il codice sotto test, mai automaticamente.
  • Entrambi gli approcci sono troppo estremi e di conseguenza non ottimali. JMockit Expectations & Verifications è l'unica API che consente allo sviluppatore di scegliere senza problemi la migliore combinazione di invocazioni fittizie rigorose (previste per impostazione predefinita) e non rigorose (consentite per impostazione predefinita) per ogni test.
  • Per essere più chiari, l'API Mockito presenta il seguente difetto. Se è necessario verificare che durante il test si sia verificata un'invocazione a un metodo mocked non void, ma il test richiede un valore restituito da quel metodo diverso da quello predefinito per il tipo restituito, il test Mockito avrà codice duplicato: una chiamata when (mock.someMethod ()). thenReturn (xyz) nella fase di registrazione e una verifica (mock) .someMethod () nella fase di verifica. Con JMockit è sempre possibile registrare un'aspettativa rigorosa, che non dovrà essere verificata esplicitamente. In alternativa, è possibile specificare un vincolo di conteggio delle chiamate (volte = 1) per qualsiasi aspettativa non rigorosa registrata (con Mockito tali vincoli possono essere specificati solo in una chiamata di verifica (mock, vincolo)).
  • Mockito ha una sintassi scadente per le verifiche in ordine e per le verifiche complete (ovvero controllare che tutte le invocazioni agli oggetti fittizi siano verificate esplicitamente). Nel primo caso, è necessario creare un oggetto aggiuntivo e su di esso vengono effettuate chiamate per la verifica: InOrder inOrder = inOrder (mock1, mock2, ...). Nel secondo caso, devono essere effettuate chiamate come verifyNoMoreInteractions (mock) o verifyZeroInteractions (mock1, mock2).
  • Con JMockit, scrivi semplicemente new VerificationsInOrder () o new FullVerifications () invece di new Verifications () (o new FullVerificationsInOrder () per combinare entrambi i requisiti). Non è necessario specificare quali oggetti fittizi sono coinvolti. Nessuna chiamata API beffarda extra. E come bonus, chiamando unverifiedInvocations () all'interno di un blocco di verifica ordinato, puoi eseguire verifiche relative agli ordini che sono semplicemente impossibili in Mockito.

Infine, JMockit Testing Toolkit ha una portata più ampia e obiettivi più ambiziosi rispetto ad altri toolkit di simulazione, al fine di fornire una soluzione di test per sviluppatori completa e sofisticata. Una buona API per il mocking, anche senza limitazioni artificiali, non è sufficiente per la creazione produttiva di test. È essenziale anche uno strumento di Code Coverage indipendente dall'IDE, facile da usare e ben integrato, ed è ciò che JMockit Coverage mira a fornire. Un altro pezzo del set di strumenti di test per sviluppatori che diventerà più utile con l'aumentare delle dimensioni della suite di test è la capacità di rieseguire in modo incrementale i test dopo una modifica localizzata al codice di produzione; anche questo è incluso nello strumento Copertura.

(concesso, la fonte potrebbe essere parziale, ma beh ...)

Direi di andare con JMockit . È il più facile da usare, flessibile e funziona praticamente per tutti i casi, anche quelli difficili e gli scenari in cui non puoi controllare la classe da testare (o non puoi romperla per motivi di compatibilità, ecc.).

Le mie esperienze con JMockit sono state molto positive.


1
Non ho mai usato jmockit, ma vorrei aggiungere un altro argomento alla discussione: dai un'occhiata a un confronto delle tendenze di Google di tutti i framework discussi. A partire dal 06.06.2012, JMockit non compare nemmeno nel grafico delle tendenze di Google rispetto a Mockito e EasyMock. E anche il numero di utenti è importante quando si sceglie un framework.
macchinari

3
È abbastanza strano. Mockito e JMockIt mi danno rispettivamente 409 'e 83' hit su Google. Sicuramente JMockIt dovrebbe apparire almeno.
thoredge

5
La tua risposta è molto utile. Avevo programmato di utilizzare semplicemente Mockito, ma ora proverò prima JMockit. Sembra troppo bello non provarlo. @machinery: Sì, è importante guardare le tendenze, ma sceglierlo come criterio principale ti limiterà al flusso principale e ti proteggerà dall'innovazione.
demone

1
So che questo è un vecchio thread, ma dopo aver letto questa recensione ho pensato di provarlo anche io. Devo dire che, in superficie, JMockit è molto promettente. Tuttavia, ad oggi, ho trovato molto carente il supporto della comunità. Sto riscontrando un grosso problema con la mia comprensione dell'API Mock e dopo aver pubblicato i miei problemi non ho avuto risposta nei 2 giorni.
Eric B.

1
La risposta ha 8 anni, quindi molte cose nella risposta non sono più corrette. Un punto è che JMockit richiede -javaagentflag a partire dalla 1.42 perché non è più possibile autoallegarsi da Java 9 e trovare soluzioni adeguate ovviamente non era nello scopo dello sviluppatore. Un altro punto è che JMockit non consente più di deridere metodi e costruttori privati ​​mentre PowerMock fa afaik.
Vampire

24

Ho lavorato sia con Mockito che con JMockit e la mia esperienza con loro è:

  • Mockito:

    • derisione implicita (-> migliore usabilità, ma ha il pericolo di non riuscire a rilevare le chiamate di metodi non consentite sui mock)
    • verifica esplicita
  • EasyMock:

    • beffardo esplicito
    • verifica implicita
  • JMockit:

    • supporta entrambi
  • Inoltre, altri vantaggi di JMockit:

    • se stai prendendo in giro metodi / costruttori statici ecc. (come l'estensione di una base di codice legacy molto vecchia senza UT), avrai due scelte: 1) Mockito / EasyMock con estensione Powermock o 2) Jmockit
    • rapporto di copertura integrato

Personalmente preferisco JMockit, che penso sia più ricco di funzionalità e flessibile, ma richiede una curva di apprendimento un po 'più ripida. Di solito ci sono diversi modi per ottenere lo stesso effetto beffardo e richiede maggiore cura durante la progettazione dei mock.


c'è stackoverflow.com/questions/8003278/... "verifyNoMoreInteractions" Suppongo che se si vuole pseudo beffardo esplicito con Mockito
rogerdpack

15

Uso jMockit solo per le sue librerie di riflessione in Deencapsultation.class. In realtà adoro lo stile di Mockito, ma mi rifiuto di cambiare il mio codice e confondere la mia API solo in modo che un framework di test limitato possa arrivarci. E sono un fan del test di tutto il mio codice, quindi un framework che non può testare facilmente metodi privati ​​non è quello che voglio usare.

Sono stato influenzato da questo articolo

Dopo una curva di apprendimento (certamente ampia), jMockit è ora il mio framework di unit test principale per i mock.


7
Forse, se senti di dover testare metodi privati, sei troppo preoccupato di come funziona il tuo codice, piuttosto che di quello che fa (che è il vero punto e che può essere determinato esercitando solo i suoi metodi pubblici). Inoltre, sarei interessato a leggere quell'articolo, ma il collegamento è interrotto.
codebox

4 anni dopo, utilizzi ancora jMockit come framework di test principale? Lo sto provando per la prima volta e incappo in alcuni problemi con esso, ma non so se sono io a fraintendere come funziona jMockit o se è una funzionalità che semplicemente non esiste.
Eric B.

jMockit non supporta più il test di metodi privati. La classe Deencapsulation è stata lentamente deprecata e quindi rimossa completamente nella versione 1.47. jmockit.github.io/changes.html
Pytry il

4

Per un facile test della nostra base di codice legacy (con molte chiamate di metodi statici, ecc.), JMockit è stato inestimabile. [Plug senza vergogna per un articolo sul mio blog]


0

Personalmente preferisco EasyMock .
La capacità di deviare tra controlli beffardi piacevoli, normali e rigorosi è una delle mie funzionalità preferite.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.