The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare
-
Upload
davide-cerbo -
Category
Technology
-
view
1.214 -
download
0
description
Transcript of The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare
![Page 1: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/html5/thumbnails/1.jpg)
![Page 2: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/html5/thumbnails/3.jpg)
Non parleremo di...
– XP Programming
– Test-Driven Development
– Agile
– Scrum
– etc etc
![Page 4: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/html5/thumbnails/4.jpg)
...ma parleremo di...
come scrivere codice
TESTABILE
perchè l'unico modo per applicare le metodologie det te in precedenza è scrivere i
TEST UNITARI
e l'unico modo per scriverli è produrre codice
TESTABILE
![Page 5: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/html5/thumbnails/5.jpg)
Definizioni assortite
Test : processo atto ad individuare carenze funzionali e n on 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 interfa cce
![Page 6: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/html5/thumbnails/7.jpg)
Esempio di codice brutto
![Page 8: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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 contestoquindi difficilmente testabili unitariamente e richiedono fatica aggiuntiva nel test con i mock object.
![Page 12: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/html5/thumbnails/21.jpg)
Testiamolo...
Totalmente non testabile in termini unitari!!!
![Page 22: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/html5/thumbnails/26.jpg)
Bibliografia
Google Testing Bloghttp://googletesting.blogspot.com/
Refactoring: Improving the Design of Existing Code (M artin 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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/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: The Hitchhiker's Guide to testable code: semplici regole per scrivere codice semplice da testare](https://reader033.fdocuments.us/reader033/viewer/2022061212/54941c85b479596f4d8b49d5/html5/thumbnails/29.jpg)
Q&A
Q&AQ&AQ&AQ&A