Introduzione a PowerMock

1. Panoramica

Il test unitario con l'aiuto di un framework beffardo è stato riconosciuto come una pratica utile da molto tempo e il framework Mockito, in particolare, ha dominato questo mercato negli ultimi anni.

E per facilitare la progettazione di codici decenti e rendere semplice l'API pubblica, alcune funzionalità desiderate sono state intenzionalmente omesse. In alcuni casi, tuttavia, queste carenze costringono i tester a scrivere codice ingombrante solo per rendere fattibile la creazione di mock.

È qui che entra in gioco il framework PowerMock.

PowerMockito è un'API di estensione di PowerMock per supportare Mockito. Fornisce funzionalità per lavorare con l'API Java Reflection in modo semplice per superare i problemi di Mockito, come la mancanza di capacità di deridere metodi finali, statici o privati.

Questo tutorial fornirà un'introduzione all'API di PowerMockito e a come viene applicata nei test.

2. Preparazione per il test con PowerMockito

Il primo passaggio per integrare il supporto PowerMock per Mockito è includere le seguenti due dipendenze nel file POM di Maven:

 org.powermock powermock-module-junit4 1.6.4 test   org.powermock powermock-api-mockito 1.6.4 test 

Successivamente, dobbiamo preparare i nostri casi di test per lavorare con PowerMockito applicando le seguenti due annotazioni:

@RunWith(PowerMockRunner.class) @PrepareForTest(fullyQualifiedNames = "com.baeldung.powermockito.introduction.*")

L' elemento fullyQualifiedNames nell'annotazione @PrepareForTest rappresenta un array di nomi completi dei tipi che vogliamo imitare. In questo caso, utilizziamo un nome di pacchetto con un carattere jolly per dire a PowerMockito di preparare tutti i tipi all'interno del pacchetto com.baeldung.powermockito.introduction per il mocking .

Ora siamo pronti per sfruttare la potenza di PowerMockito .

3. Costruttori beffardi e metodi finali

In questa sezione, dimostreremo i modi per ottenere un'istanza fittizia invece di una reale quando si crea un'istanza di una classe con l' operatore new , e quindi utilizzare quell'oggetto per deridere un metodo finale. La classe collaborante, i cui costruttori e metodi finali saranno derisi, è definita come segue:

public class CollaboratorWithFinalMethods { public final String helloMethod() { return "Hello World!"; } }

Innanzitutto, creiamo un oggetto fittizio utilizzando l' API PowerMockito :

CollaboratorWithFinalMethods mock = mock(CollaboratorWithFinalMethods.class);

Successivamente, imposta un'aspettativa che dica che ogni volta che viene invocato il costruttore no-arg di quella classe, deve essere restituita un'istanza fittizia anziché una reale:

whenNew(CollaboratorWithFinalMethods.class).withNoArguments().thenReturn(mock);

Vediamo come funziona questo mocking di costruzione in azione istanziando la classe CollaboratorWithFinalMethods usando il suo costruttore predefinito e quindi verificando i comportamenti di PowerMock:

CollaboratorWithFinalMethods collaborator = new CollaboratorWithFinalMethods(); verifyNew(CollaboratorWithFinalMethods.class).withNoArguments();

Nella fase successiva, un'aspettativa è impostata sul metodo finale:

when(collaborator.helloMethod()).thenReturn("Hello Baeldung!");

Questo metodo viene quindi eseguito:

String welcome = collaborator.helloMethod();

Le seguenti asserzioni confermano che il metodo helloMethod è stato chiamato sull'oggetto collaboratore e restituisce il valore impostato dall'aspettativa beffarda:

Mockito.verify(collaborator).helloMethod(); assertEquals("Hello Baeldung!", welcome);

Se vogliamo deridere un metodo finale specifico piuttosto che tutti quelli finali all'interno di un oggetto, il metodo Mockito.spy (oggetto T) può tornare utile. Ciò è illustrato nella sezione 5.

4. Metodi statici beffardi

Supponiamo di voler deridere i metodi statici di una classe denominata CollaboratorWithStaticMethods. Questa classe è dichiarata come segue:

public class CollaboratorWithStaticMethods { public static String firstMethod(String name) { return "Hello " + name + " !"; } public static String secondMethod() { return "Hello no one!"; } public static String thirdMethod() { return "Hello no one again!"; } }

Per deridere questi metodi statici, dobbiamo registrare la classe che lo racchiude con l' API di PowerMockito :

mockStatic(CollaboratorWithStaticMethods.class);

In alternativa, possiamo utilizzare il metodo Mockito.spy (Class class) per deridere uno specifico come dimostrato nella sezione seguente.

Successivamente, le aspettative possono essere impostate per definire i valori che i metodi devono restituire quando vengono richiamati:

when(CollaboratorWithStaticMethods.firstMethod(Mockito.anyString())) .thenReturn("Hello Baeldung!"); when(CollaboratorWithStaticMethods.secondMethod()).thenReturn("Nothing special");

Oppure può essere impostata un'eccezione da lanciare quando si chiama il metodo thirdMethod :

doThrow(new RuntimeException()).when(CollaboratorWithStaticMethods.class); CollaboratorWithStaticMethods.thirdMethod();

Ora è il momento di eseguire i primi due metodi:

String firstWelcome = CollaboratorWithStaticMethods.firstMethod("Whoever"); String secondWelcome = CollaboratorWithStaticMethods.firstMethod("Whatever");

Invece di chiamare i membri della classe reale, le chiamate precedenti vengono delegate ai metodi del mock. Le seguenti affermazioni dimostrano che la simulazione è entrata in vigore:

assertEquals("Hello Baeldung!", firstWelcome); assertEquals("Hello Baeldung!", secondWelcome);

Siamo anche in grado di verificare i comportamenti dei metodi del mock, incluso quante volte viene invocato un metodo. In questo caso, firstMethod è stato chiamato due volte, mentre secondMethod non ha mai:

verifyStatic(Mockito.times(2)); CollaboratorWithStaticMethods.firstMethod(Mockito.anyString()); verifyStatic(Mockito.never()); CollaboratorWithStaticMethods.secondMethod();

Nota: il metodo verifyStatic deve essere chiamato subito prima di qualsiasi verifica del metodo statico affinché PowerMockito sappia che il successivo richiamo del metodo è ciò che deve essere verificato.

Infine, il metodo statico thirdMethod dovrebbe generare una RuntimeException come dichiarato prima nel mock. È convalidato dall'elemento previsto dell'annotazione @Test :

@Test(expected = RuntimeException.class) public void givenStaticMethods_whenUsingPowerMockito_thenCorrect() { // other methods CollaboratorWithStaticMethods.thirdMethod(); }

5. Derisione parziale

Invece di deridere un'intera classe, l' API PowerMockito consente di deridere una parte di essa utilizzando il metodo spia . La seguente classe verrà utilizzata come collaboratore per illustrare il supporto di PowerMock per il mocking parziale:

public class CollaboratorForPartialMocking { public static String staticMethod() { return "Hello Baeldung!"; } public final String finalMethod() { return "Hello Baeldung!"; } private String privateMethod() { return "Hello Baeldung!"; } public String privateMethodCaller() { return privateMethod() + " Welcome to the Java world."; } }

Iniziamo prendendo in giro un metodo statico, che è chiamato staticMethod nella definizione di classe sopra. Innanzitutto, utilizza l' API PowerMockito per deridere parzialmente la classe CollaboratorForPartialMocking e impostare un'aspettativa per il suo metodo statico:

spy(CollaboratorForPartialMocking.class); when(CollaboratorForPartialMocking.staticMethod()).thenReturn("I am a static mock method.");

Viene quindi eseguito il metodo statico:

returnValue = CollaboratorForPartialMocking.staticMethod();

Il comportamento beffardo viene verificato come segue:

verifyStatic(); CollaboratorForPartialMocking.staticMethod();

La seguente asserzione conferma che il metodo mock è stato effettivamente chiamato confrontando il valore restituito con l'aspettativa:

assertEquals("I am a static mock method.", returnValue);

Ora è il momento di passare ai metodi finali e privati. Per illustrare la parziale derisione di questi metodi, dobbiamo istanziare la classe e dire all'API di PowerMockito di spiarla :

CollaboratorForPartialMocking collaborator = new CollaboratorForPartialMocking(); CollaboratorForPartialMocking mock = spy(collaborator);

Gli oggetti creati sopra sono usati per dimostrare la beffa sia del metodo finale che di quello privato. Tratteremo ora il metodo finale impostando un'aspettativa e invocando il metodo:

when(mock.finalMethod()).thenReturn("I am a final mock method."); returnValue = mock.finalMethod();

Il comportamento di deridere parzialmente quel metodo è dimostrato:

Mockito.verify(mock).finalMethod();

Un test verifica che la chiamata al metodo finalMethod restituirà un valore che corrisponde all'aspettativa:

assertEquals("I am a final mock method.", returnValue);

Un processo simile viene applicato al metodo privato. La differenza principale è che non possiamo richiamare direttamente questo metodo dal caso di test. Fondamentalmente, un metodo privato deve essere chiamato da altri della stessa classe. Nella classe CollaboratorForPartialMocking , il metodo privateMethod deve essere richiamato dal metodo privateMethodCaller e utilizzeremo quest'ultimo come delegato. Cominciamo con l'aspettativa e l'invocazione:

when(mock, "privateMethod").thenReturn("I am a private mock method."); returnValue = mock.privateMethodCaller();

Si conferma la beffa del metodo privato:

verifyPrivate(mock).invoke("privateMethod");

Il seguente test assicura che il valore restituito dall'invocazione del metodo privato sia lo stesso dell'aspettativa:

assertEquals("I am a private mock method. Welcome to the Java world.", returnValue);

6. Conclusione

Questo tutorial ha fornito un'introduzione all'API di PowerMockito , dimostrando il suo utilizzo nella risoluzione di alcuni dei problemi che gli sviluppatori incontrano quando utilizzano il framework Mockito.

L'implementazione di questi esempi e frammenti di codice può essere trovata nel progetto GitHub collegato.