davide cerbo - [email protected] - jug roma nicola raglia - [email protected] - jug roma the...
TRANSCRIPT
![Page 1: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/1.jpg)
![Page 2: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/2.jpg)
Davide Cerbo - [email protected] - JUG RomaNicola Raglia - [email protected] - JUG Roma
The Hitchhiker's Guide to
testable code
semplici regole per scrivere codice semplice da testare
The Hitchhiker's Guide to
testable code
![Page 3: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/3.jpg)
Non parleremo di...
– XP Programming
– Test-Driven Development
– Agile
– Scrum
– etc etc
![Page 4: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/4.jpg)
...ma parleremo di...
come scrivere codice
TESTABILE
perchè l'unico modo per applicare le metodologie dette in precedenza è scrivere i
TEST UNITARI
e l'unico modo per scriverli è produrre codice
TESTABILE
![Page 5: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/5.jpg)
Definizioni assortite
Test: processo atto ad individuare carenze funzionali e non funzionali durante la fase di sviluppo del software.
Test Unitario: è un test atto a verificare una componente elementare del software possibilmente in termini di isolamento dalle dipendenze
Refactoring: è il processo che prevede una ristrutturazione del codice modificando il meno possibile le interfacce
![Page 6: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/6.jpg)
Ancora definizioni assortite
Design Pattern: soluzione progettuale generale a un problema ricorrente Mock Object: oggetti destinati a simulare il comportamento di oggetti reali.Durante il test con i mock object abbiamo:
o creazione mocko definizione del comportamento del mock objecto esecuzione del testo verifica del comportamento del mock object
![Page 7: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/7.jpg)
Esempio di codice brutto
![Page 8: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/8.jpg)
Iniziamo dal costruttore
public RubricaImpl(Properties properties, ApplicationContext applicationContext) { this.user = applicationContext.getAuthenticationContext().getUser(); this.url = properties.getProperty("url"); this.userName = properties.getProperty("userName"); this.password = properties.getProperty("password"); try { this.connection = DriverManager.getConnection(url, userName, password); } catch (SQLException e) { //gestione eccezione } this.database = new DatabaseImpl(connection); }
![Page 9: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/9.jpg)
Il nostro primo (non) Unit Testpublic void testConstructor() throws Exception { Properties properties = new Properties(); properties.load(new FileInputStream("database.properties")); ApplicationContext applicationContext = ApplicationContext.getContext(); Rubrica rubrica = new RubricaImpl(properties, applicationContext); }
con i Mock Objects:public void testConstructor() throws Exception { Properties properties = new Properties(); properties.setProperty("user", "dbuser"); properties.setProperty("password","dbpassword"); properties.setProperty("url", "jdbc:db:///test"); ApplicationContext applicationContext = createMock(ApplicationContext.class); AuthenticationContext authContext = createMock(AuthenticationContext.class); expect(applicationContext.getAuthenticationContext()).andReturn(authContext); expect(authContext.getUser()).andReturn(createMock(User.class)); replay(authContext, applicationContext); Rubrica rubrica = new RubricaImpl(properties, applicationContext); verify(authContext, applicationContext); }
![Page 10: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/10.jpg)
Rispettiamo la legge
public RubricaImpl(String url, String userName, String password, User user) { this.user = user; this.url = url; this.userName = userName; this.password = password; Connection connection=DriverManager.getConnection(url,userName,password); this.database = new DatabaseImpl(connection); }
Per rispettare la legge di Demeter un oggetto può solo invocare i metodi:• propri• dei suoi parametri• di ogni oggetto che crea• delle sue variabili
![Page 11: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/11.jpg)
Mai dire CONTEXT
public RubricaImpl(Properties properties, ApplicationContext applicationContext) { this.user = applicationContext.getUser(); this.url = properties.getProperty("url"); ....... .......} public RubricaImpl(String url, String userName, String password, User user) { this.user = user; this.url = url; ....... .......}
applicationContext e properties sono oggetti di contesto
quindi difficilmente testabili unitariamente e richiedono fatica aggiuntiva nel test con i mock object.
![Page 12: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/12.jpg)
Vietato affaticare
public RubricaImpl(String url, String userName, String password, User user) { ..... this.userName = userName; Connection connection = DriverManager.getConnection(url,userName,password); this.database = new DatabaseImpl(connection); }
public RubricaImpl(String url, String userName, String password, User user) { ..... this.userName = userName; this.database = DatabaseManager.getDatabase(url,userName,password); }
Questa è una soluzione ma non va bene perché si usa un
metodo statico
![Page 13: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/13.jpg)
Solo l'indispensabile
public RubricaImpl(String url, String userName, String password, User user) { this.userName =userName; this.database = DatabaseManager.getDatabase(url,userName,password); }
public RubricaImpl(User user) { this.user = user; this.database = DatabaseSingleton.getInstance(); }
Ecco fatta un po' di pulizia!Non era giusto far conoscere alla Rubrica le informazioni per
accedere al database!
Ma è spuntato un singleton e questo è male!
2 SOLUZIONI DA EVITARE!!!
![Page 14: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/14.jpg)
Dependency Injection
public RubricaImpl(Database database, User user) { this.user = user; this.database = database; }
Il costruttore è stato alleggerito da responsabilità non proprie.
Ma ora come lo usiamo?
![Page 15: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/15.jpg)
Pattern Abstract Factory
public class RubricaFactoryImpl implements RubricaFactory { private final DatabaseFactory databaseFactory;
public RubricaFactoryImpl(DatabaseFactory databaseFactory) { this.databaseFactory = databaseFactory; }
public Rubrica getRubrica(User user) { return new RubricaImpl(databaseFactory.getDatabase(), user); }
} La responsabilità di creare oggetti sarà sempre data
ad una Factory o ad altri pattern creazionali.
![Page 16: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/16.jpg)
Passiamo al Database public class DatabaseFactoryImpl implements DataBaseFactory { private final Properties properties; public DatabaseFactoryImpl(Properties properties) { this.properties = properties; } public Database getDatabase(){ String url = properties.getProperty("url"); String userName = properties.getProperty("userName"); String password = properties.getProperty("password"); Connection connection = null; try { connection = DriverManager.getConnection(url, userName, password); } catch (SQLException e) { //gestione eccezione } return new DatabaseImpl(connection); }}
DatabaseFactoryImpl non è testabile, andrebbe fatto ulteriore refactoring, ma il
tempo è poco :(
![Page 17: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/17.jpg)
Il Test (quasi) finale (1/2)
public void testConstructor() throws Exception { Database database = createMock(Database.class); User user = createMock(User.class); replay(database, user); Rubrica rubrica = new RubricaImpl(database, user); verify(database, user); }
Non c'è bisogno di descrivere comportamento per gli oggetti mock perchè il costruttore non fa niente altro
che costruire l'oggetto.Ma le factory appena create?
![Page 18: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/18.jpg)
Il Test (quasi) finale (2/2)
public void testFactory() throws Exception { DatabaseFactory databaseFactory = createMock(DatabaseFactory.class); Database database = createMock(Database.class); User user = createMock(User.class); expect(databaseFactory.getDatabase()).andReturn(database); replay(databaseFactory, user, database); RubricaFactory rubricaFactory = new RubricaFactoryImpl(databaseFactory); Rubrica rubrica = rubricaFactory.getRubrica(user); verify(databaseFactory, user, database); assertNotNull(rubrica); }
![Page 19: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/19.jpg)
Gli obbiettivi raggiunti
Single responsability Assegnare la giusta responsabilità Utilizzare la Dependency Injection Dividere il fare dal creare Evitare stati globali Design by Interface
![Page 20: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/20.jpg)
Andiamo avanti...
public void publish(){ Context context = new InitialContext(); Object reference = context.lookup("PublisherService"); PublisherEjb home = (PublishEjb)PortableRemoteObject.narrow(reference,PublishEjb.class); PublisherService publisher = home.create(); publisher.publish(this); }
![Page 21: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/21.jpg)
Testiamolo...
Totalmente non testabile in termini unitari!!!
![Page 22: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/22.jpg)
Via il Sevice Locator
public RubricaImpl(Database database, User user, PublisherService publisher) { this.user = user; this.database = database; this.publisher = publisher; }
public void publish(){ this.publisher.publish(this); }
Iniettiamo una classe che abbia la responsabilità di pubblicare. Nel nostro caso lo farà tramite EJB, ma sarà semplice sostituire la tecnologia.
![Page 23: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/23.jpg)
Ancora non è finita...
public RubricaImpl(Database database, User user) { this.user = user; this.database = database; }
public void publishWith(PublisherService publisher){ publisher.publish(this);
}
Passare l'oggetto PublisherService al costruttore è errato perché non è necessario al normale ciclo di vita della Rubrica, ma serve solo nel caso di una richiesta di pubblicazione
![Page 24: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/24.jpg)
Problema solo spostato
Abbiamo solo spostato il problema, infatti l'implementazione PublisherServiceEJB sarà intestabile unitariamente...
...ma fortunatamente la nuova specifica EJB 3.0 ci viene in aiuto eliminando il ServiceLocator
Ma non è lo scopo di questo talk spiegare come :D
![Page 25: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/25.jpg)
Il Test finale
public void testPublish() throws Exception { Database database = createMock(Database.class); User user = createMock(User.class); replay(database, user); Rubrica rubrica = new RubricaImpl(database, user); verify(database, user);
PublisherService publisherService = createMock(PublisherService.class); publisherService.publish(rubrica); replay(publisherService, user); rubrica.publishWith(publisherService); verify(publisherService, user); }
![Page 26: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/26.jpg)
Bibliografia
Google Testing Bloghttp://googletesting.blogspot.com/
Refactoring: Improving the Design of Existing Code (Martin Fowler)http://www.refactoring.com/
Refactoring Workbook (William C. Wake)http://xp123.com/rwb/
Applicare UML e Pattern (Craig Larman)http://www.craiglarman.com
Principi di ingegneria del software (Pressman)http://highered.mcgraw-hill.com/sites/0072853182/
Wikipediahttp://www.wikipedia.org
![Page 27: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/27.jpg)
Strumenti utili
Unit Test:www.junit.org
Test code coverage:http://cobertura.sourceforge.net/http://emma.sourceforge.net/
Testability:http://code.google.com/p/testability-explorer/http://testabilityexplorer.org/report
Mock objects: http://www.easymock.org/http://www.jmock.org/http://code.google.com/p/mockito/
![Page 28: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/28.jpg)
I nostri contatti
Davide [email protected]@pro-netics.comhttp://jesty.it
Nicola [email protected]@pro-netics.comhttp://sourcengineering.org
![Page 29: Davide Cerbo - davidecerbo@gmail.com - JUG Roma Nicola Raglia - n.raglia@gmail.com - JUG Roma The Hitchhiker's Guide to testable code semplici regole](https://reader036.vdocuments.mx/reader036/viewer/2022081602/5542eb77497959361e8e143f/html5/thumbnails/29.jpg)
Q&A
Q&AQ&AQ&AQ&A