TEST-DRIVEN DEVELOPMENT Ennio Masi – 961/85 Prof. Sergio Di Martino Ingegneria del software 2 – 2007/08
Sommario Cos’è il TDD? Il TDD e l’XP Unit Testing e xUnit Framework TDD Mantra I princìpi TDD Patterns Legacy code I tipi di test Benefici e limiti
Cos’è? Test-Driven Development Test-First Programming Test-Driven Design
Cos’è? (2) E’ una tecnica iterativa di  sviluppo  del software. L’obiettivo del TDD è il  design  del software, non la sua  validazione .
TDD e l’XP Il TDD è una  pratica  agile. L’XP è una  metodologia  agile.
TDD e l’XP (2) Il TDD nasce dall’estrazione di due concetti fondamentali dell’XP: Test First Programming Refactoring
TDD e l’XP (3) Il TDD è il cuore dell’ Extreme Programming . TDD può essere applicato senza l’aggiunta delle altre pratiche dell’XP. L’XP segna una strada da seguire per essere preparati ai cambiamenti futuri. Il TDD cerca di controllare il gap tra le decisioni ed i feedback durante lo sviluppo.
Obiettivi del TDD Rendere lo sviluppo migliore e più rapido. Mantenere il codice sempre documentato. Ottenere codice flessibile e facilmente estendibile. Diminuire la presenza di bug nel codice di produzione.
Unit Testing e xUnit Framework
Unit Test Un test  non  è di unità se: comunica con il database comunica in rete modifica il database non può essere lanciato in parallelo ad altri test bisogna effettuare diverse operazioni per lanciare il test “ Unit tests run fast. If they don’t run fast, they aren’t unit tests.”
Unit Test ed il TDD Sono rilasciati con il codice di produzione. Nel TDD una funzionalità è rilasciata soltanto se vi è associata almeno uno Unit Test. Consentono di effettuare il refactoring di una funzionalità senza “paura”. Meno debugging.
I Mock Objects Un mock object è una simulazione di un oggetto reale. Implementa l’interfaccia dell’oggetto da simulare ed ha il suo stesso comportamento. Forniscono una risposta pre-impostata. Servono per capire se l’oggetto che li usa lo fa correttamente. Utilissimi per testare unità senza legarsi ad oggetti esterni.
I Mock Objects (2) Per superare una validazione utilizzando i mock, gli oggetti che li usano devono chiamare il metodo corretto con i parametri giusti e nell’ordine che ci aspettiamo. ( mock’s validation ) Un oggetto che semplicemente simula un oggetto reale, senza effettuare la verifica detta al punto precedente non è un mock, è uno  stub . Esistono implementazioni dei Mock Objects per moltissimi linguaggi. (  http://www.mockobjects.com   )
Esempio Utilizzare un mock in questo caso consente di effettuare il testing  senza  l’ausilio del vero database di produzione. Il mock deve avere la stessa interfaccia dell’oggetto che implementa il database e lo stesso comportamento dalla prospettiva del software client. L’esempio classico è quello di implementare un mock object che simuli la connessione ad  un database:
Esempio (2) DBConnection.java public   interface  DBConnection { void  connect(); void  close(); } public   class  MockDBConnection  implements  DBConnection { private   boolean  connected = false; private   boolean  closed = false; public void  connect() {connected = true;} public void  close() {closed = true;} public boolean  validate(){ return  connected && closed;} } MockDBConnection.java
xUnit Framework Ha diversi utilizzi Design del software Implementazione del codice Debugging Ottimizzazione delle performance Quality Assurance (QA) E’ un tool software che consente di scrivere e lanciare unit test. E’ il core del TDD
xUnit Framework (2) JUnit CppUnit Nunit PyUnit vbUnit … Nel 1999 Kent Beck presentò uno unit test framework per il linguaggio  Smalltalk  (SUnit) Da quel framework sono stati effettuati molti porting:
L’architettura
Assert Dal seminario su JUnit: “ Gli Assert sono metodi che consentono di asserire che una certa condizione è vera o falsa.”
Assert (2) assertTrue([message], condition)  : Il test è superato se la condizione è vera assertFalse([message], condition)  : Il test è superato se la condizione è falsa assertNull([message], Object)  : Il test è superato se il riferimento all’oggetto è NULL. assertNotNull([message], Object)  : il test è superato se il riferimento all’oggetto non è NULL. assertEquals([message], value1, value2)  : il test è superato se value1 == value2. assertNotEquals([message], value1, value2)  : il test è superato se non vale che value1 == value2 fail()  : wrapper di assertTrue(false)
Assert (3) (Teoria) Una regola generale è che ogni test deve contenere soltanto un assert. (Pratica) Spesso i metodi di test contengono più assert oppure assert singoli ma composti da più condizioni legate da operatori logici.
Testing degli errori public   void   testXXX () { try { //an operation fail(“eccezione non avvenuta”) } catch  (Exception e) {} ... } Questo test genera un’eccezione e controlla che sia gestito come ci aspettiamo. Nell’esempio ci aspettiamo che sia lanciata l’eccezione nel momento i  cui è chiamata  anOperation . Il test fallisce se l’eccezione non avviene, mentre va a buon fine se l’eccezione viene lanciata. fail  è equivalente ad  assertTrue(false ) ma è più leggibile. E’ fondamentale testare la gestione degli errori. Viene utilizzato il metodo  fail .
Testing degli errori (2) public   void   testXXX () { try { //an operation } catch  (Exception e) { fail(e.getMessage()); } ... } E’ fondamentale testare la gestione degli errori. Viene utilizzato il metodo  fail . Questo test genera un’eccezione e controlla che sia gestito come ci aspettiamo. In questo esempio ci aspettiamo che  non  sia lanciata l’eccezione nel momento in cui è chiamata  anOperation . Il test fallisce se l’eccezione avviene, mentre va a buon fine se l’eccezione non viene lanciata. fail  è equivalente ad  assertTrue(false ) ma è più leggibile.
Il processo di sviluppo: TDD Mantra
Le regole d’oro del TDD Si scrive nuovo codice solo se un test automatico è fallito. Eliminare i duplicati. Test-First Programming + Refactoring
Implicazioni tecniche Ogni programmatore scrive i propri test. Fornire risposte rapide ai piccoli cambiamenti. Codice con alta coesione e basso accoppiamento, altrimenti risulta difficile fare i test.
TDD Mantra Primo step Think Think  : ragionare per piccoli passi Focalizzarsi sul  comportamento  che il codice deve avere.
TDD Mantra Think “ Vogliamo sviluppare una libreria aritmetica che agisca solo su numeri non negativi” Esempio aritLib.py
TDD Mantra Think Esempio Ragioniamo sulla somma: Se in input vi sono due numeri non negativi, ritorniamo  la somma. Se  almeno  uno dei due input è negativo allora ritorna -1
TDD Mantra Secondo step Think Red Bar  : scrittura dei test. Focalizzarsi sul  comportamento  della classe e la sua interfaccia pubblica. Red bar
TDD Mantra Secondo step Think import  aritLib import  unittest class   AritLibTest ( unittest.TestCase ): knownValues = ((0, 0, 0), (1, 1, 2), (2, 3, 5), (-1, -1, -1), (-10, 10, -1),(10, -5, -1), ) def   testAdd ( self ): for  x, y, sum  in   self .knownValues: result = aritLib.add(x, y) self .assertEquals(sum, result) Red bar
TDD Mantra Secondo step Think ERROR : testAdd (__main__.AritLibTest) ---------------------------------------------------------------------- Traceback (most recent call last): File “AritLibTest.py”, line 11, in testAdd result = aritLib.add(x,y) AttributeError : 'module' object has no attribute 'add' ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED  (errors=1) Red bar class   AritLibTest ( unittest.TestCase ): knownValues = ((0, 0, 0), (1, 1, 2), (2, 3, 5), (-1, -1, -1), (-10, 10, -1),(10, -5, -1), ) def   testAdd ( self ): for  x, y, sum  in   self .knownValues: result = aritLib.add(x, y) self .assertEquals(sum, result) IL TEST FALLISCE PERCHE’ LA FUNZIONE ANCORA NON ESISTE!
TDD Mantra Terzo step Think Red bar Green Bar Test fallito Green Bar  : scrittura del codice. Scrivere  solo  il codice necessario per superare i test scritti in precedenza.
TDD Mantra Terzo step Think Red bar Green Bar Test fallito aritLib.py def   add (x, y): if  x < 0: return  -1 if  y < 0: return  -1 return  x+y
TDD Mantra Terzo step Think Red bar Green Bar Test fallito aritLib.py def   add (x, y): if  x < 0: return  -1 if  y < 0: return  -1 return  x+y ---------------------------------------------------------------------- Ran 1 test in 0.000 s ---------------------------------------------------------------------- OK Vengono lanciati i test scritti in precedenza  senza modificarli.
TDD Mantra Quarto step Think Red bar Green Bar Test fallito Refactoring Refactoring  : semplificare ed aggiustare il desing della funzionalità sviluppata. In questa fase non bisogna assolutamente modificare la semantica della funzionalità implementata!
TDD Mantra Quarto step Think Red bar Green Bar Test fallito Prima def   add (x, y): if  x < 0: return  -1 if  y < 0: return  -1 return  x+y Refactoring Dopo def   add (x, y): if  x < 0  or  y < 0: return  -1 return  x+y
TDD Mantra Quarto step Think Red bar Green Bar Test fallito Refactoring Dopo def   add (x, y): if  x < 0  or  y < 0: return  -1 return  x+y ---------------------------------------------------------------------- Ran 1 test in 0.000 s ---------------------------------------------------------------------- OK Vengono lanciati i test scritti in precedenza  senza modificarli.
I princìpi Think Red bar Green Bar Test fallito Refactoring “ Code once, test twice” “ Clean code that works” KISS: Keep It Short & Simple YAGNI: You Ain’t Gonna Need It
Quando fermarsi? Quando il sistema effettivamente funziona. Il sistema ha superato il 100% dei test. Non c’è codice duplicato. Il sistema dovrebbe avere meno classi e metodi possibile.
Bad smells … C’è qualcosa che non va se … E’ necessario testare metodi privati/protetti. Necessitiamo di testing White Box. E’ necessario configurare il sistema prima di lanciare i test. I test funzionano ad intermittenza. I test sono molto lenti.
Implicazioni sociali Il TDD consente di “gestire” le paure durante lo sviluppo. La paura ha molti aspetti negativi durante lo sviluppo: rende incerti toglie la voglia di comunicare rende timorosi davanti ai feedback rende nervosi
Implicazioni sociali (2) Il TDD consente di gestire le “paure” durante lo sviluppo: si procede al rilascio del codice solo se ha superato il 100% dei test previsti. Il design va sempre di pari passo con lo sviluppo. Il TDD consente ai programmatori di conoscere perfettamente il codice.
La velocità Nel TDD è importante la velocità con la quale i test sono eseguiti. Se i test non fossero veloci allora sarebbero una distrazione. Se i test non fossero veloci allora non sarebbero lanciati con alta frequenza: che vantaggio avrebbe il TDD? “ Unit tests run fast. If they don’t run fast, they aren’t unit tests.”
Le linee guida
TDD Patterns Red Bar patterns : Comincia da un test semplice. Se hai un’idea nuova aggiungi il test alla lista ma rimani su quello che stai facendo. Aggiungi un test per ogni difetto trovato. Se non riesci ad andare avanti butta via tutto e riscrivilo.
TDD Patterns Testing patterns : Se il test richiede troppo tempo per funzionare allora dividilo in parti più semplici. Se i test hanno bisogno di oggetti complessi allora usa i mock objects. Mantieni il log dell’esecuzione dei test. Se lavori solo lascia rotto l’ultimo test della giornata. Se lavori in team lascia sempre i test funzionanti.
TDD Patterns Green Bar patterns : Scrivi il codice più semplice per passare il test. Scrivi l’implementazione più ovvia per superare il/i test corrente/i. Se un’operazione lavora su collezioni allora scrivi l’implementazione prima sul singolo oggetto e dopo generalizza.
Focused integration testing  ed  End-to-End testing
Focused integration testing Un  focused integration test  è focalizzato a testare: la comunicazione con il database la comunicazione in rete la comunicazione con il filesystem la comunicazione con oggetti esterni Gli unit test da soli non bastano, il codice deve comunicare con l’esterno.
Focused integration testing (2) Se necessitiamo di molti integration tests  allora c’è qualcosa che non va. Es.  Se tutte i business object parlano direttamente con il database allora il codice non ha un buon design! Il codice che  parla  con l’esterno non è né ben coeso nè ben accoppiato.
Focused integration testing (2) Se necessitiamo di molti integration tests  allora c’è qualcosa che non va. Es. Se tutte i business object parlano direttamente con il database allora il codice non ha un buon design! Il codice che  parla  con l’esterno non è né ben coeso nè ben accoppiato. Un miglior design prevede che vi sia un’unica classe che parli con il database.
End-to-end Testing Serve per testare l’intero sistema: Test di intere  storie  di utilizzo del sistema, dalla GUI utente all’utilizzo del database … Contro : Difficile da portare a termine. Difficile da settare. Difficile individuare gli errori. Molto lento. Non automatizzabile.
La velocità di esecuzione dei test Unit tests  : un centinaio al secondo. Focused integration tests  : una decina al secondo. End-to-end tests  : diversi secondi per ogni singol test.
Il TDD ed il Legacy Code
Legacy Code Problemi: Mancanza di documentazione Difficile da capire in profondità Non è progettato pensando alla “testabilità” “ Legacy code is code without tests”
Legacy Code (2) I passi per affrontare il legacy code: Inizia a scrivere test per capire se il legacy code (una sua parte) è stato ben compreso. Adatta il test finchè non funziona  bene .
Legacy Code (3) Problemi: Quanto codice è stato testato ? Quali aree necessitano di testing ? Quali sono i rischi del codice? Difficile avere una visione d’insieme del codice
Benefici del TDD Si mantiene il codice semplice Sviluppo rapido I test sono sia design che documentazione Facile comprensione del codice Bug trovati presto nello sviluppo Meno debugging Basso costo dei cambiamenti
Limiti del TDD Curva di apprendimento alta I manager sono restii ad applicarlo Richiede una grande disciplina Difficile applicarlo alle GUI Di difficile applicazione a Legacy Code
Riferimenti Test-Driven Development: By Examples  Kent Beck 2002 Test-Driven Development: A pratical guide  Astels Unit Test Frameworks  Paul Hamill

Introduzione al Test Driven Development

  • 1.
    TEST-DRIVEN DEVELOPMENT EnnioMasi – 961/85 Prof. Sergio Di Martino Ingegneria del software 2 – 2007/08
  • 2.
    Sommario Cos’è ilTDD? Il TDD e l’XP Unit Testing e xUnit Framework TDD Mantra I princìpi TDD Patterns Legacy code I tipi di test Benefici e limiti
  • 3.
    Cos’è? Test-Driven DevelopmentTest-First Programming Test-Driven Design
  • 4.
    Cos’è? (2) E’una tecnica iterativa di sviluppo del software. L’obiettivo del TDD è il design del software, non la sua validazione .
  • 5.
    TDD e l’XPIl TDD è una pratica agile. L’XP è una metodologia agile.
  • 6.
    TDD e l’XP(2) Il TDD nasce dall’estrazione di due concetti fondamentali dell’XP: Test First Programming Refactoring
  • 7.
    TDD e l’XP(3) Il TDD è il cuore dell’ Extreme Programming . TDD può essere applicato senza l’aggiunta delle altre pratiche dell’XP. L’XP segna una strada da seguire per essere preparati ai cambiamenti futuri. Il TDD cerca di controllare il gap tra le decisioni ed i feedback durante lo sviluppo.
  • 8.
    Obiettivi del TDDRendere lo sviluppo migliore e più rapido. Mantenere il codice sempre documentato. Ottenere codice flessibile e facilmente estendibile. Diminuire la presenza di bug nel codice di produzione.
  • 9.
    Unit Testing exUnit Framework
  • 10.
    Unit Test Untest non è di unità se: comunica con il database comunica in rete modifica il database non può essere lanciato in parallelo ad altri test bisogna effettuare diverse operazioni per lanciare il test “ Unit tests run fast. If they don’t run fast, they aren’t unit tests.”
  • 11.
    Unit Test edil TDD Sono rilasciati con il codice di produzione. Nel TDD una funzionalità è rilasciata soltanto se vi è associata almeno uno Unit Test. Consentono di effettuare il refactoring di una funzionalità senza “paura”. Meno debugging.
  • 12.
    I Mock ObjectsUn mock object è una simulazione di un oggetto reale. Implementa l’interfaccia dell’oggetto da simulare ed ha il suo stesso comportamento. Forniscono una risposta pre-impostata. Servono per capire se l’oggetto che li usa lo fa correttamente. Utilissimi per testare unità senza legarsi ad oggetti esterni.
  • 13.
    I Mock Objects(2) Per superare una validazione utilizzando i mock, gli oggetti che li usano devono chiamare il metodo corretto con i parametri giusti e nell’ordine che ci aspettiamo. ( mock’s validation ) Un oggetto che semplicemente simula un oggetto reale, senza effettuare la verifica detta al punto precedente non è un mock, è uno stub . Esistono implementazioni dei Mock Objects per moltissimi linguaggi. ( http://www.mockobjects.com )
  • 14.
    Esempio Utilizzare unmock in questo caso consente di effettuare il testing senza l’ausilio del vero database di produzione. Il mock deve avere la stessa interfaccia dell’oggetto che implementa il database e lo stesso comportamento dalla prospettiva del software client. L’esempio classico è quello di implementare un mock object che simuli la connessione ad un database:
  • 15.
    Esempio (2) DBConnection.javapublic interface DBConnection { void connect(); void close(); } public class MockDBConnection implements DBConnection { private boolean connected = false; private boolean closed = false; public void connect() {connected = true;} public void close() {closed = true;} public boolean validate(){ return connected && closed;} } MockDBConnection.java
  • 16.
    xUnit Framework Hadiversi utilizzi Design del software Implementazione del codice Debugging Ottimizzazione delle performance Quality Assurance (QA) E’ un tool software che consente di scrivere e lanciare unit test. E’ il core del TDD
  • 17.
    xUnit Framework (2)JUnit CppUnit Nunit PyUnit vbUnit … Nel 1999 Kent Beck presentò uno unit test framework per il linguaggio Smalltalk (SUnit) Da quel framework sono stati effettuati molti porting:
  • 18.
  • 19.
    Assert Dal seminariosu JUnit: “ Gli Assert sono metodi che consentono di asserire che una certa condizione è vera o falsa.”
  • 20.
    Assert (2) assertTrue([message],condition) : Il test è superato se la condizione è vera assertFalse([message], condition) : Il test è superato se la condizione è falsa assertNull([message], Object) : Il test è superato se il riferimento all’oggetto è NULL. assertNotNull([message], Object) : il test è superato se il riferimento all’oggetto non è NULL. assertEquals([message], value1, value2) : il test è superato se value1 == value2. assertNotEquals([message], value1, value2) : il test è superato se non vale che value1 == value2 fail() : wrapper di assertTrue(false)
  • 21.
    Assert (3) (Teoria)Una regola generale è che ogni test deve contenere soltanto un assert. (Pratica) Spesso i metodi di test contengono più assert oppure assert singoli ma composti da più condizioni legate da operatori logici.
  • 22.
    Testing degli erroripublic void testXXX () { try { //an operation fail(“eccezione non avvenuta”) } catch (Exception e) {} ... } Questo test genera un’eccezione e controlla che sia gestito come ci aspettiamo. Nell’esempio ci aspettiamo che sia lanciata l’eccezione nel momento i cui è chiamata anOperation . Il test fallisce se l’eccezione non avviene, mentre va a buon fine se l’eccezione viene lanciata. fail è equivalente ad assertTrue(false ) ma è più leggibile. E’ fondamentale testare la gestione degli errori. Viene utilizzato il metodo fail .
  • 23.
    Testing degli errori(2) public void testXXX () { try { //an operation } catch (Exception e) { fail(e.getMessage()); } ... } E’ fondamentale testare la gestione degli errori. Viene utilizzato il metodo fail . Questo test genera un’eccezione e controlla che sia gestito come ci aspettiamo. In questo esempio ci aspettiamo che non sia lanciata l’eccezione nel momento in cui è chiamata anOperation . Il test fallisce se l’eccezione avviene, mentre va a buon fine se l’eccezione non viene lanciata. fail è equivalente ad assertTrue(false ) ma è più leggibile.
  • 24.
    Il processo disviluppo: TDD Mantra
  • 25.
    Le regole d’orodel TDD Si scrive nuovo codice solo se un test automatico è fallito. Eliminare i duplicati. Test-First Programming + Refactoring
  • 26.
    Implicazioni tecniche Ogniprogrammatore scrive i propri test. Fornire risposte rapide ai piccoli cambiamenti. Codice con alta coesione e basso accoppiamento, altrimenti risulta difficile fare i test.
  • 27.
    TDD Mantra Primostep Think Think : ragionare per piccoli passi Focalizzarsi sul comportamento che il codice deve avere.
  • 28.
    TDD Mantra Think“ Vogliamo sviluppare una libreria aritmetica che agisca solo su numeri non negativi” Esempio aritLib.py
  • 29.
    TDD Mantra ThinkEsempio Ragioniamo sulla somma: Se in input vi sono due numeri non negativi, ritorniamo la somma. Se almeno uno dei due input è negativo allora ritorna -1
  • 30.
    TDD Mantra Secondostep Think Red Bar : scrittura dei test. Focalizzarsi sul comportamento della classe e la sua interfaccia pubblica. Red bar
  • 31.
    TDD Mantra Secondostep Think import aritLib import unittest class AritLibTest ( unittest.TestCase ): knownValues = ((0, 0, 0), (1, 1, 2), (2, 3, 5), (-1, -1, -1), (-10, 10, -1),(10, -5, -1), ) def testAdd ( self ): for x, y, sum in self .knownValues: result = aritLib.add(x, y) self .assertEquals(sum, result) Red bar
  • 32.
    TDD Mantra Secondostep Think ERROR : testAdd (__main__.AritLibTest) ---------------------------------------------------------------------- Traceback (most recent call last): File “AritLibTest.py”, line 11, in testAdd result = aritLib.add(x,y) AttributeError : 'module' object has no attribute 'add' ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED (errors=1) Red bar class AritLibTest ( unittest.TestCase ): knownValues = ((0, 0, 0), (1, 1, 2), (2, 3, 5), (-1, -1, -1), (-10, 10, -1),(10, -5, -1), ) def testAdd ( self ): for x, y, sum in self .knownValues: result = aritLib.add(x, y) self .assertEquals(sum, result) IL TEST FALLISCE PERCHE’ LA FUNZIONE ANCORA NON ESISTE!
  • 33.
    TDD Mantra Terzostep Think Red bar Green Bar Test fallito Green Bar : scrittura del codice. Scrivere solo il codice necessario per superare i test scritti in precedenza.
  • 34.
    TDD Mantra Terzostep Think Red bar Green Bar Test fallito aritLib.py def add (x, y): if x < 0: return -1 if y < 0: return -1 return x+y
  • 35.
    TDD Mantra Terzostep Think Red bar Green Bar Test fallito aritLib.py def add (x, y): if x < 0: return -1 if y < 0: return -1 return x+y ---------------------------------------------------------------------- Ran 1 test in 0.000 s ---------------------------------------------------------------------- OK Vengono lanciati i test scritti in precedenza senza modificarli.
  • 36.
    TDD Mantra Quartostep Think Red bar Green Bar Test fallito Refactoring Refactoring : semplificare ed aggiustare il desing della funzionalità sviluppata. In questa fase non bisogna assolutamente modificare la semantica della funzionalità implementata!
  • 37.
    TDD Mantra Quartostep Think Red bar Green Bar Test fallito Prima def add (x, y): if x < 0: return -1 if y < 0: return -1 return x+y Refactoring Dopo def add (x, y): if x < 0 or y < 0: return -1 return x+y
  • 38.
    TDD Mantra Quartostep Think Red bar Green Bar Test fallito Refactoring Dopo def add (x, y): if x < 0 or y < 0: return -1 return x+y ---------------------------------------------------------------------- Ran 1 test in 0.000 s ---------------------------------------------------------------------- OK Vengono lanciati i test scritti in precedenza senza modificarli.
  • 39.
    I princìpi ThinkRed bar Green Bar Test fallito Refactoring “ Code once, test twice” “ Clean code that works” KISS: Keep It Short & Simple YAGNI: You Ain’t Gonna Need It
  • 40.
    Quando fermarsi? Quandoil sistema effettivamente funziona. Il sistema ha superato il 100% dei test. Non c’è codice duplicato. Il sistema dovrebbe avere meno classi e metodi possibile.
  • 41.
    Bad smells …C’è qualcosa che non va se … E’ necessario testare metodi privati/protetti. Necessitiamo di testing White Box. E’ necessario configurare il sistema prima di lanciare i test. I test funzionano ad intermittenza. I test sono molto lenti.
  • 42.
    Implicazioni sociali IlTDD consente di “gestire” le paure durante lo sviluppo. La paura ha molti aspetti negativi durante lo sviluppo: rende incerti toglie la voglia di comunicare rende timorosi davanti ai feedback rende nervosi
  • 43.
    Implicazioni sociali (2)Il TDD consente di gestire le “paure” durante lo sviluppo: si procede al rilascio del codice solo se ha superato il 100% dei test previsti. Il design va sempre di pari passo con lo sviluppo. Il TDD consente ai programmatori di conoscere perfettamente il codice.
  • 44.
    La velocità NelTDD è importante la velocità con la quale i test sono eseguiti. Se i test non fossero veloci allora sarebbero una distrazione. Se i test non fossero veloci allora non sarebbero lanciati con alta frequenza: che vantaggio avrebbe il TDD? “ Unit tests run fast. If they don’t run fast, they aren’t unit tests.”
  • 45.
  • 46.
    TDD Patterns RedBar patterns : Comincia da un test semplice. Se hai un’idea nuova aggiungi il test alla lista ma rimani su quello che stai facendo. Aggiungi un test per ogni difetto trovato. Se non riesci ad andare avanti butta via tutto e riscrivilo.
  • 47.
    TDD Patterns Testingpatterns : Se il test richiede troppo tempo per funzionare allora dividilo in parti più semplici. Se i test hanno bisogno di oggetti complessi allora usa i mock objects. Mantieni il log dell’esecuzione dei test. Se lavori solo lascia rotto l’ultimo test della giornata. Se lavori in team lascia sempre i test funzionanti.
  • 48.
    TDD Patterns GreenBar patterns : Scrivi il codice più semplice per passare il test. Scrivi l’implementazione più ovvia per superare il/i test corrente/i. Se un’operazione lavora su collezioni allora scrivi l’implementazione prima sul singolo oggetto e dopo generalizza.
  • 49.
    Focused integration testing ed End-to-End testing
  • 50.
    Focused integration testingUn focused integration test è focalizzato a testare: la comunicazione con il database la comunicazione in rete la comunicazione con il filesystem la comunicazione con oggetti esterni Gli unit test da soli non bastano, il codice deve comunicare con l’esterno.
  • 51.
    Focused integration testing(2) Se necessitiamo di molti integration tests allora c’è qualcosa che non va. Es. Se tutte i business object parlano direttamente con il database allora il codice non ha un buon design! Il codice che parla con l’esterno non è né ben coeso nè ben accoppiato.
  • 52.
    Focused integration testing(2) Se necessitiamo di molti integration tests allora c’è qualcosa che non va. Es. Se tutte i business object parlano direttamente con il database allora il codice non ha un buon design! Il codice che parla con l’esterno non è né ben coeso nè ben accoppiato. Un miglior design prevede che vi sia un’unica classe che parli con il database.
  • 53.
    End-to-end Testing Serveper testare l’intero sistema: Test di intere storie di utilizzo del sistema, dalla GUI utente all’utilizzo del database … Contro : Difficile da portare a termine. Difficile da settare. Difficile individuare gli errori. Molto lento. Non automatizzabile.
  • 54.
    La velocità diesecuzione dei test Unit tests : un centinaio al secondo. Focused integration tests : una decina al secondo. End-to-end tests : diversi secondi per ogni singol test.
  • 55.
    Il TDD edil Legacy Code
  • 56.
    Legacy Code Problemi:Mancanza di documentazione Difficile da capire in profondità Non è progettato pensando alla “testabilità” “ Legacy code is code without tests”
  • 57.
    Legacy Code (2)I passi per affrontare il legacy code: Inizia a scrivere test per capire se il legacy code (una sua parte) è stato ben compreso. Adatta il test finchè non funziona bene .
  • 58.
    Legacy Code (3)Problemi: Quanto codice è stato testato ? Quali aree necessitano di testing ? Quali sono i rischi del codice? Difficile avere una visione d’insieme del codice
  • 59.
    Benefici del TDDSi mantiene il codice semplice Sviluppo rapido I test sono sia design che documentazione Facile comprensione del codice Bug trovati presto nello sviluppo Meno debugging Basso costo dei cambiamenti
  • 60.
    Limiti del TDDCurva di apprendimento alta I manager sono restii ad applicarlo Richiede una grande disciplina Difficile applicarlo alle GUI Di difficile applicazione a Legacy Code
  • 61.
    Riferimenti Test-Driven Development:By Examples Kent Beck 2002 Test-Driven Development: A pratical guide Astels Unit Test Frameworks Paul Hamill