SlideShare a Scribd company logo
PowerMock
TDD User Group - Milano 03/10/2017
Massimo Groppelli
Cos’è PowerMock
PowerMock è un potente framework Java, che permette di scrivere test unitari per del codice che
normalmente non sarebbe testabile.
PowerMock estende alcuni tra i più famosi framework di mocking disponibili per il linguaggio come
EasyMock e Mockito. In questo talk ci occuperemo dell’integrazione con Mockito, ovvero PowerMockito.
Principali funzionalità che PowerMock aggiunge a Mockito:
● Mocking di classi finali, metodi statici e costruttori.
● Verifica delle invocazioni di metodi privati.
● Soppressione di comportamenti indesiderati (side effects) di metodi e classi.
PowerMock implementa le funzionalità sopra elencate, grazie alla combinazione di molteplici tecniche, a
partire dalla semplice introspezione tramite reflection per arrivare ad un classloader personalizzato ed
alla manipolazione del bytecode tramite instrumentazione.
Due parole su Mockito
Mockito è il più famoso framework di mocking per Java ed una tra le 10 librerie più utilizzate in assoluto
per il linguaggio.
● E’ un framework intuitivo, flessibile e divertente da utilizzare.
● Si basa su un approccio No expect-run-verify, non ha il concetto di expectation, ma solo le fasi di
stubbing e verification sui collaboratori.
● Si possono creare due tipologie di test doubles, i mock e gli spy per il partial mocking che come
vedremo è molto importante in ottica PowerMock.
@Test
public void test()
{
// Fixture.
final MyInterface mockDependency = Mockito.mock(MyInterface.class);
// Stubbing.
Mockito.when(mockDependency.method(Mockito.eq("testparam"))).thenReturn("testresult");
// Run Test.
final String result = new SystemUnderTest(mockDependency).methodToTest("testparam");
// Assertion.
Assert.assertEquals("Composizione stringa risultato", "prefix-testresult-suffix", result);
// Verification.
Mockito.verify(mockDependency, Mockito.times(1)).method(Mockito.eq("testparam"));
}
Ecosistema dei test
TEST DI ACCETTAZIONE
Funziona tutto il sistema?
(Altre definizioni: functional, customer, system tests)
TEST DI INTEGRAZIONE
Funziona il nostro codice rispetto a del
codice che non possiamo modificare?
(framework pubblico / librerie di altri gruppi di lavoro)
TEST UNITARI
I nostri oggetti svolgono correttamente le
loro responsabilità ed è comodo utilizzarli?
Classificazione livelli di test:
Growing Object-Oriented Software, Guided by Tests
PowerMock è uno strumento che si può utilizzare durante la scrittura di test di integrazione e soprattutto
unitari che misurano la qualità interna (codice facile da capire e da modificare) del sistema.
Perché questo talk?
Vorrei condividere la mia esperienza rispondendo ad un pò di domande……..
● PowerMock serve solo per testare codice di legacy e/o scritto male?
● Quanto il design delle nostre applicazioni dipende da limiti degli strumenti che utilizziamo per i test?
● Come PowerMock influenza le scelte di design?
● Può PowerMock aiutarci nel processo di refactor e come?
● Può mancare uno strumento come PowerMock nella cassetta degli attrezzi di chi pratica la TDD?
PowerMock è la chiave per eliminare il concetto di design testabile.
Design testabile e buon design
DESIGN TESTABILE
Il design testabile misura quanto è facile testare il codice, NON se è possibile testarlo.
Regole per isolare in modo semplice e veloce il codice sotto test dal resto del sistema.
● Istanziare una classe.
● Sostituire un’implementazione.
● Simulare differenti scenari.
● Invocare sul S.U.T (System under test) uno specifico flusso di controllo dal codice di test.
BUON DESIGN Spesso un design testabile corrisponde ad un buon design, ma non sempre.
Linee guida del design testabile
● Evitare metodi privati complessi, testare solo metodi pubblici.
● Evitare classi e metodi finali, non si possono creare sottotipi.
● Evitare metodi static se richiesta sostituzione in futuro.
● Utilizzare la keyword new con molta attenzione, è alto il rischio di creare accoppiamento.
● Evitare di gestire la logica che potrebbe essere sostituita nel costruttore.
● Evitare di creare singleton, meglio creare componenti con scope singleton.
● Favorire il riuso del codice per composizione, l’ereditarietà ok per polimorfismo, non per il riuso del
codice.
● Creare wrapper sulle librerie di terze parti, niente mocking su codice che non ci appartiene.
Più il codice è difficile da testare e più sarà difficile da modificare al prossimo cambio di requisiti!
Effetti collaterali
CLASSI E METODI FINALI
Critica: Una classe dovrebbe essere pensata per essere estesa.
Effetto: Si rinuncia ad un buon design per i limiti del tool di test.
Mockito nella versione 2 ha introdotto la possibilità di creare mock su classi final.
METODI PRIVATI
Critica: In alcuni contesti serve testare o verificare lo stato interno di un componente.
Effetto: Si cambia la visibilità di alcuni metodi per la fase di test.
L’annotazione @VisibleForTesting di Guava è stata creata proprio per documentare questa
violazione dell’incapsulamento.
Effetti collaterali
CLASSI E METODI STATICI
Critica: Alcune responsabilità sono statiche di natura e non siamo maghi per prevedere il futuro.
Effetto: Nel dubbio si rinuncia a creare classi statiche anche quando si dovrebbe.
Tante factory non statiche, codice scomodo da gestire ed aumento footprint.
WRAPPER DI LIBRERIE
Critica: E’ costoso fare classi wrapper ogni volta che si deve utilizzare codice che non ci
appartiene.
Effetto: Tendenza a creare molte classi senza valore aggiunto che fanno aumentare la codebase.
Si reinventa la ruota.
Metodi statici e classi finali
public class NewUserService
{
private final UserRepository userRepo;
public NewUserService(UserRepository userRepo)
{
this.userRepo = userRepo;
}
public User createNewUser(String name)
{
// Utilizzo metodo statico.
String newRandomTmpPwd = User.newTempPassword(20);
final User user = new User(name, newRandomTmpPwd);
// Collaborazione con il repository.
this.userRepo.saveOrUpdate(user);
return user;
}
}
Metodi statici e classi finali
Metodi statici e classi finali
@RunWith(PowerMockRunner.class)
@PrepareForTest( { UserRepository.class, User.class })
public class NewUserServiceTest
{
@Test
public void test()
{
// Fixture.
UserRepository mockUserRepo = PowerMockito.mock(UserRepository.class);
User newUserExpected = new User("massimo", "newPwdForTest");
// Stubbing.
PowerMockito.mockStatic(User.class);
Mockito.when(User.newTempPassword(Mockito.anyInt())).thenReturn("newPwdForTest");
// Run Test.
NewUserService serviceUnderTest = new NewUserService(mockUserRepo);
User newUserResult = serviceUnderTest.createNewUser("massimo");
// Assertion.
Assert.assertEquals(newUserExpected, newUserResult);
// Verification.
Mockito.verify(mockUserRepo, Mockito.times(1)).saveOrUpdate(Mockito.eq(newUserExpected));
}
}
Metodi privati
public class PrivateMethodClass
{
public int bigMethod(String argStr, int argInt) throws IOException
{
return this.privateToTest(argStr, argInt) + 10;
}
private int privateToTest(String argStr, int argInt) throws IOException
{
int newArgInt = this.privateToStub(argStr);
this.execute(newArgInt, argInt);
return newArgInt + 10;
}
private int privateToStub(String string)
{
return string.length() + 1000;
}
private void execute(int arg1, int arg2) throws IOException
{
try( BufferedWriter newBufferedWriter = Files.newBufferedWriter(Paths.get("myFile.txt"));)
{
newBufferedWriter.write(String.valueOf(arg1 + arg2)); // side effects.
}
}
}
Metodi privati
@RunWith(PowerMockRunner.class)
@PrepareForTest(PrivateMethodClass.class)
public class PrivateMethodExampleTest
{
@Test
public void testPrivateMethod() throws Exception
{
// Fixture.
PrivateMethodClass classUnderTest = PowerMockito.spy(new PrivateMethodClass());
// - No side effects.
Method method = PowerMockito.method(PrivateMethodClass.class, "execute", int.class, int.class);
PowerMockito.suppress(method);
// Stubbing.
PowerMockito.doReturn(20).when(classUnderTest, "privateToStub", "param");
// Run Test.
int result = Whitebox.invokeMethod(classUnderTest, "privateToTest", "param", 10);
// Assertion.
Assert.assertEquals(30, result);
// Verification.
PowerMockito.verifyPrivate(classUnderTest, Mockito.times(1)).invoke("execute", 20, 10);
}
}
Difetti di PowerMock
● Non è uno strumento per principianti.
● Si rischia di creare troppe dipendenze implicite.
● Può mandare in crash la JVM solamente per una annotazione messa nel posto sbagliato.
● Stack di difficile comprensione in debug.
● Va in conflitto con altri tools che a loro volta manipolano il bytecode a runtime, come succede per
alcuni framework di code coverage. E’ in corso una migrazione a ByteBuddy per risolvere il problema.

More Related Content

ODP
PDF
Java Unit Testing - JUnit (1)
PDF
Java Unit Testing - JUnit (2)
PDF
Software Testing e TDD
PPTX
Dependency injection: the good parts
PDF
Java Unit Testing - Introduction
PDF
Java Unit Testing - In container and database testing
PDF
Lezione 3: Sviluppo in Extreme Programming
Java Unit Testing - JUnit (1)
Java Unit Testing - JUnit (2)
Software Testing e TDD
Dependency injection: the good parts
Java Unit Testing - Introduction
Java Unit Testing - In container and database testing
Lezione 3: Sviluppo in Extreme Programming

What's hot (12)

PDF
Una fugace occhiata al Test Driven Development (2006)
PDF
Baby Steps TripServiceKata
PPTX
Codice di qualità con VS2010 (TDD)
PDF
Metodi asincroni in spring
PPTX
Unit Testing
PDF
Unit Testing
PDF
Meetup Code Garden Roma e Java User Group Roma: metodi asincroni con Spring -...
PDF
Lezione 4: I tool Ant e Subversion
PDF
Software testing with mocking framework (Android App)
PDF
Lezione 7: Design Pattern Comportamentali
PDF
TDD patterns and TDD strategies
PDF
Googletest, tdd e mock
Una fugace occhiata al Test Driven Development (2006)
Baby Steps TripServiceKata
Codice di qualità con VS2010 (TDD)
Metodi asincroni in spring
Unit Testing
Unit Testing
Meetup Code Garden Roma e Java User Group Roma: metodi asincroni con Spring -...
Lezione 4: I tool Ant e Subversion
Software testing with mocking framework (Android App)
Lezione 7: Design Pattern Comportamentali
TDD patterns and TDD strategies
Googletest, tdd e mock
Ad

Similar to PowerMock TDD User Group Milano (20)

PPTX
Test Driven Development @ Xe.Net
PDF
The Hitchhiker's Guide to testable code: semplici regole per scrivere codice ...
PPT
Unit Testing Mockito
PPTX
Unit Test di Gabriele Seroni
PDF
Presentazione Testing automatizzato
PPT
Introduzione al Test Driven Development
PPT
Programmazione a oggetti tramite la macchina del caffé (pt. 3)
PPTX
PDF
Redefining the Role of the Test Engineer: The Path to a New Era | DevFest Mil...
PDF
05 unit testing
PPTX
BDD in DDD
ODP
TDD Casi Studio
PPTX
ODP
Workshop: Introduzione ad TDD
PPTX
Validazione Degli Oggetti Di Dominio
ODP
Unit testing 101
PDF
Come scrivere software SOLID(O)
PDF
Come scrivere software SOLID(O)
PDF
Test Driven Development for iOS
PPTX
Inversion of Control @ CD2008
Test Driven Development @ Xe.Net
The Hitchhiker's Guide to testable code: semplici regole per scrivere codice ...
Unit Testing Mockito
Unit Test di Gabriele Seroni
Presentazione Testing automatizzato
Introduzione al Test Driven Development
Programmazione a oggetti tramite la macchina del caffé (pt. 3)
Redefining the Role of the Test Engineer: The Path to a New Era | DevFest Mil...
05 unit testing
BDD in DDD
TDD Casi Studio
Workshop: Introduzione ad TDD
Validazione Degli Oggetti Di Dominio
Unit testing 101
Come scrivere software SOLID(O)
Come scrivere software SOLID(O)
Test Driven Development for iOS
Inversion of Control @ CD2008
Ad

PowerMock TDD User Group Milano

  • 1. PowerMock TDD User Group - Milano 03/10/2017 Massimo Groppelli
  • 2. Cos’è PowerMock PowerMock è un potente framework Java, che permette di scrivere test unitari per del codice che normalmente non sarebbe testabile. PowerMock estende alcuni tra i più famosi framework di mocking disponibili per il linguaggio come EasyMock e Mockito. In questo talk ci occuperemo dell’integrazione con Mockito, ovvero PowerMockito. Principali funzionalità che PowerMock aggiunge a Mockito: ● Mocking di classi finali, metodi statici e costruttori. ● Verifica delle invocazioni di metodi privati. ● Soppressione di comportamenti indesiderati (side effects) di metodi e classi. PowerMock implementa le funzionalità sopra elencate, grazie alla combinazione di molteplici tecniche, a partire dalla semplice introspezione tramite reflection per arrivare ad un classloader personalizzato ed alla manipolazione del bytecode tramite instrumentazione.
  • 3. Due parole su Mockito Mockito è il più famoso framework di mocking per Java ed una tra le 10 librerie più utilizzate in assoluto per il linguaggio. ● E’ un framework intuitivo, flessibile e divertente da utilizzare. ● Si basa su un approccio No expect-run-verify, non ha il concetto di expectation, ma solo le fasi di stubbing e verification sui collaboratori. ● Si possono creare due tipologie di test doubles, i mock e gli spy per il partial mocking che come vedremo è molto importante in ottica PowerMock. @Test public void test() { // Fixture. final MyInterface mockDependency = Mockito.mock(MyInterface.class); // Stubbing. Mockito.when(mockDependency.method(Mockito.eq("testparam"))).thenReturn("testresult"); // Run Test. final String result = new SystemUnderTest(mockDependency).methodToTest("testparam"); // Assertion. Assert.assertEquals("Composizione stringa risultato", "prefix-testresult-suffix", result); // Verification. Mockito.verify(mockDependency, Mockito.times(1)).method(Mockito.eq("testparam")); }
  • 4. Ecosistema dei test TEST DI ACCETTAZIONE Funziona tutto il sistema? (Altre definizioni: functional, customer, system tests) TEST DI INTEGRAZIONE Funziona il nostro codice rispetto a del codice che non possiamo modificare? (framework pubblico / librerie di altri gruppi di lavoro) TEST UNITARI I nostri oggetti svolgono correttamente le loro responsabilità ed è comodo utilizzarli? Classificazione livelli di test: Growing Object-Oriented Software, Guided by Tests PowerMock è uno strumento che si può utilizzare durante la scrittura di test di integrazione e soprattutto unitari che misurano la qualità interna (codice facile da capire e da modificare) del sistema.
  • 5. Perché questo talk? Vorrei condividere la mia esperienza rispondendo ad un pò di domande…….. ● PowerMock serve solo per testare codice di legacy e/o scritto male? ● Quanto il design delle nostre applicazioni dipende da limiti degli strumenti che utilizziamo per i test? ● Come PowerMock influenza le scelte di design? ● Può PowerMock aiutarci nel processo di refactor e come? ● Può mancare uno strumento come PowerMock nella cassetta degli attrezzi di chi pratica la TDD? PowerMock è la chiave per eliminare il concetto di design testabile.
  • 6. Design testabile e buon design DESIGN TESTABILE Il design testabile misura quanto è facile testare il codice, NON se è possibile testarlo. Regole per isolare in modo semplice e veloce il codice sotto test dal resto del sistema. ● Istanziare una classe. ● Sostituire un’implementazione. ● Simulare differenti scenari. ● Invocare sul S.U.T (System under test) uno specifico flusso di controllo dal codice di test. BUON DESIGN Spesso un design testabile corrisponde ad un buon design, ma non sempre.
  • 7. Linee guida del design testabile ● Evitare metodi privati complessi, testare solo metodi pubblici. ● Evitare classi e metodi finali, non si possono creare sottotipi. ● Evitare metodi static se richiesta sostituzione in futuro. ● Utilizzare la keyword new con molta attenzione, è alto il rischio di creare accoppiamento. ● Evitare di gestire la logica che potrebbe essere sostituita nel costruttore. ● Evitare di creare singleton, meglio creare componenti con scope singleton. ● Favorire il riuso del codice per composizione, l’ereditarietà ok per polimorfismo, non per il riuso del codice. ● Creare wrapper sulle librerie di terze parti, niente mocking su codice che non ci appartiene. Più il codice è difficile da testare e più sarà difficile da modificare al prossimo cambio di requisiti!
  • 8. Effetti collaterali CLASSI E METODI FINALI Critica: Una classe dovrebbe essere pensata per essere estesa. Effetto: Si rinuncia ad un buon design per i limiti del tool di test. Mockito nella versione 2 ha introdotto la possibilità di creare mock su classi final. METODI PRIVATI Critica: In alcuni contesti serve testare o verificare lo stato interno di un componente. Effetto: Si cambia la visibilità di alcuni metodi per la fase di test. L’annotazione @VisibleForTesting di Guava è stata creata proprio per documentare questa violazione dell’incapsulamento.
  • 9. Effetti collaterali CLASSI E METODI STATICI Critica: Alcune responsabilità sono statiche di natura e non siamo maghi per prevedere il futuro. Effetto: Nel dubbio si rinuncia a creare classi statiche anche quando si dovrebbe. Tante factory non statiche, codice scomodo da gestire ed aumento footprint. WRAPPER DI LIBRERIE Critica: E’ costoso fare classi wrapper ogni volta che si deve utilizzare codice che non ci appartiene. Effetto: Tendenza a creare molte classi senza valore aggiunto che fanno aumentare la codebase. Si reinventa la ruota.
  • 10. Metodi statici e classi finali
  • 11. public class NewUserService { private final UserRepository userRepo; public NewUserService(UserRepository userRepo) { this.userRepo = userRepo; } public User createNewUser(String name) { // Utilizzo metodo statico. String newRandomTmpPwd = User.newTempPassword(20); final User user = new User(name, newRandomTmpPwd); // Collaborazione con il repository. this.userRepo.saveOrUpdate(user); return user; } } Metodi statici e classi finali
  • 12. Metodi statici e classi finali @RunWith(PowerMockRunner.class) @PrepareForTest( { UserRepository.class, User.class }) public class NewUserServiceTest { @Test public void test() { // Fixture. UserRepository mockUserRepo = PowerMockito.mock(UserRepository.class); User newUserExpected = new User("massimo", "newPwdForTest"); // Stubbing. PowerMockito.mockStatic(User.class); Mockito.when(User.newTempPassword(Mockito.anyInt())).thenReturn("newPwdForTest"); // Run Test. NewUserService serviceUnderTest = new NewUserService(mockUserRepo); User newUserResult = serviceUnderTest.createNewUser("massimo"); // Assertion. Assert.assertEquals(newUserExpected, newUserResult); // Verification. Mockito.verify(mockUserRepo, Mockito.times(1)).saveOrUpdate(Mockito.eq(newUserExpected)); } }
  • 13. Metodi privati public class PrivateMethodClass { public int bigMethod(String argStr, int argInt) throws IOException { return this.privateToTest(argStr, argInt) + 10; } private int privateToTest(String argStr, int argInt) throws IOException { int newArgInt = this.privateToStub(argStr); this.execute(newArgInt, argInt); return newArgInt + 10; } private int privateToStub(String string) { return string.length() + 1000; } private void execute(int arg1, int arg2) throws IOException { try( BufferedWriter newBufferedWriter = Files.newBufferedWriter(Paths.get("myFile.txt"));) { newBufferedWriter.write(String.valueOf(arg1 + arg2)); // side effects. } } }
  • 14. Metodi privati @RunWith(PowerMockRunner.class) @PrepareForTest(PrivateMethodClass.class) public class PrivateMethodExampleTest { @Test public void testPrivateMethod() throws Exception { // Fixture. PrivateMethodClass classUnderTest = PowerMockito.spy(new PrivateMethodClass()); // - No side effects. Method method = PowerMockito.method(PrivateMethodClass.class, "execute", int.class, int.class); PowerMockito.suppress(method); // Stubbing. PowerMockito.doReturn(20).when(classUnderTest, "privateToStub", "param"); // Run Test. int result = Whitebox.invokeMethod(classUnderTest, "privateToTest", "param", 10); // Assertion. Assert.assertEquals(30, result); // Verification. PowerMockito.verifyPrivate(classUnderTest, Mockito.times(1)).invoke("execute", 20, 10); } }
  • 15. Difetti di PowerMock ● Non è uno strumento per principianti. ● Si rischia di creare troppe dipendenze implicite. ● Può mandare in crash la JVM solamente per una annotazione messa nel posto sbagliato. ● Stack di difficile comprensione in debug. ● Va in conflitto con altri tools che a loro volta manipolano il bytecode a runtime, come succede per alcuni framework di code coverage. E’ in corso una migrazione a ByteBuddy per risolvere il problema.

Editor's Notes

  • #2: Massimo Groppelli
  • #3: PowerMock è molto semplice da utilizzare soprattutto per chi già conosce Mockito, infatti il framework non mira a reinventare la ruota ma si integra molto bene tanto è vero che le API sono praticamente uguali a quelle dei framework di Mocking che estende.
  • #8: Dire che alcune linee guida sono validissime e vanno rispettate.