Upload
giacomo-petronio
View
479
Download
2
Embed Size (px)
DESCRIPTION
Citation preview
Unit Testing
Giacomo Petronio – O3 Enterprise
https://github.com/hijackit/swtesting
Intro
Software Testing:
◦ È una buona idea?
◦ Processo costoso
tempo, conoscenza
manutenzione
Vantaggi??
Perché (1) QA
Software Di Qualità!
◦ Correttezza, robustezza, affidabilità, …
◦ Manutenibilità evolutiva, correttiva, riusabilità
1 Bug meno qualità!
N Bug …
Perché (2)
Domanda: perché?
Risposta: per verificare che ‘funziona’.
Problema Programma (soluzione)
Problema risolto?
Funziona??
Troppo generico..
Quand’è che funziona?
Quando saprò se risolve il mio problema?
Si da per scontato che saremo in grado di dire se la nostra soluzione funziona
Quando funziona?
Soddisfa i requisiti
Insieme dei requisiti
Soluzione problema
Programma funziona
1° step: definizione dei requisiti
Contratto che il SW deve rispettare
I test possono essere considerati come un modo per catturare e implementare i requisiti
Requisiti e test
Una cosa sola
1 requisito 1+ test
1 requisito, 0 test == 0 requisiti
Categorie di test
Test di accettazione
(Stress test)
Test funzionali
Test di integrazione
Unit test
Criterio:
Oggetto sotto verifica
Scopo della verifica
Unit test
Scopo: “funziona”?
Oggetto: singola classe
Altre caratteristiche:
◦ Code coverage
Unit test
API Design
Documentazione vivente
Unit test
Refactoring
Code confidence
Regression testing
Definire Unit Test
Non dovrebbe
◦ Comunicare con DBMS/rete/filesystem
◦ Aver bisogno di un ambiente configurato
Dovrebbe essere
◦ Veloce
◦ Ripetibile
◦ Indipendente
Definire Unit Test
Meno pignoli!
◦ Può accedere a DBMS (in-memory dbms)
◦ Può accedere al filesystem
◦ Può accedere alla rete
Velocità Ripetibilità Indipendenza
xUnit
JUnit
CppUnit
NUnit
PHPUnit
PyUnit
…
Idea di base
La ricetta per un buon test
◦ Fixture (contesto)
◦ Test case
◦ Check
Kent Beck’s testing framework paper http://www.xprogramming.com/testfram.htm
JUnit
MyClassTest
◦ Fixture: @Before method
◦ Test Case: @Test method
◦ Check assert
ESEMPIO…
Best practices
N model classes N test classes
Assert precisi
assertTrue(shape.area != 0); assertTrue(shape.area == 50);
Best practices
White box / Black box
Process proc = new Process(); proc.start(); assertEquals(proc.status, Status.Running);
assertTrue(proc.isRunning());
Best practices
Come testare metodi privati ◦ non testare
◦ reflection
◦ cambiare visibilità
◦ (nested test-class)
Reflection Legacy code?
Non testare Codice nuovo?
Visibilità default
Nuova classe
Best practices
Nome classe
◦ TriangleTest
Package
◦ src/main/java/it/units/inginf/shapes
Triangle.class
Rectangle.class
◦ src/test/java/it/units/inginf/shapes
TriangleTest.class
RectangleTest.class
Best practices
Nome test-case (metodi)
◦ Verbosità è ok
test01(){ … } test02(){ … }
testAreaIsEmpty(){ … } testTriangleIsNotARectangle(){ … }
areaShouldBeEmpty(){ … } areaShouldBeExactly50(){ … } triangleShouldNotBeEqualToARectangle(){ … }
Best practices
Eccezioni
◦ Attributo expected
@Test(expected=IllegalArgumentException.class) invaldAddressShouldNotBeAccepted(){ WebClient client = new WebClient(“WRONG!”); }
@Test invaldAddressShouldNotBeAccepted(){ try{ WebClient client = new WebClient(“WRONG!”); fail(); } catch(IllegalArgumentException e){} }
Tecniche di testing
Classi di equivalenza e valori al confine
◦ Coprire tutti gli input
◦ Minimizzare la ridondanza
0 6 16 65
4€ 0€ 8€ 5€
5 test-case, uno per classe di equivalenza
8 test-case, uno per confine di ciascuna classe
Tecniche di testing
Esplorazione del grafo
◦ Macchine a stato
◦ Transazioni e stato interno
int left = 1; int right = 1; public void incLeft(){ left++; } public void incRight(){ right++; } public String getId(){ return left + “.” + right; }
Tecniche di testing
1:1
2:1
3:1 1:2
1:2
2:1 1:3
T1 T2
Stato iniziale X;Y X;Y
Evento incLeft incRight
Effetto X++ Y++
Stato finale X+1;Y X;Y+1
1° livello: 2 test-case 2° livello: 4 test-case 3° livello: 8 test-case …
T1 T2
Codice testabile
SOLID principles
◦ Single responsibility
◦ Open/Closed
Codice testabile
SOLID principles
◦ Liskov substitution
AClass { client.doGreatThings(); }
Client { … }
SubClient extends Client { … }
Codice testabile
SOLID principles
◦ Interface segregation
IDoOneThing { doOneThingA(); }
IDoManyThings { doThingA(); doThingB(); doThingC(); }
IDoAnotherThing { doOneThingB(); }
Codice testabile
SOLID principles
◦ Dependency inversion
class JapaneseGuy { playWith(PlayStation ps){ ps.play(); } }
class JapaneseGuy { playWith(IConsolle c){ c.play(); } }
Concrete, Abstract
Concrete Abstract
Esempio
MovieLister
+ moviesDirectedBy
<<Interface>> MovieFinder
+ findAll()
MovieFinderImpl <<crea>>
Classe concreta usa classe concreta
http://martinfowler.com/articles/injection.html
Testare una classe
Isolare la classe
◦ Individuare tutte le dipendenze
◦ Prendere il controllo (IoC)
Classe testabile
◦ Poche dipendenze
◦ Dipendenze astratte
Inversion Of Control (IoC)
Dipendenze vengono fornite
Diversi pattern
◦ Dependency Injection (DI)
MovieLister
<<Interface>> MovieFinder
MovieFinderImpl <<crea>>
Assembler <<crea>>
<<inject>>
IoC: Dependency Injection
Constructor injection
◦ Dipendenze esplicite
Setter injection
◦ Dipendenze meno esplicite
◦ Rende testabile classe esistente
Framework…
◦ Guice
◦ Spring
◦ CDI (J2EE 6)
IoC: Service Locator
MovieLister
<<Interface>> MovieFinder
MovieFinderImpl <<crea>>
ServiceLocator Assembler
<<crea>>
<<chiede>>
DI Framework: Guice
Es. servizio di pagamento
https://code.google.com/p/google-guice/wiki/Motivation
RealBillingService
<<Interface>> CreditCardProcessor
PaypalProcessor
<<Interface>> TransactionLog
DBTransactionLog
<<Interface>> BillingService
+ chargeOrder(order, creditCard)
Stub e Mock
Isolare la classe
Se ha dipendenze?
◦ Sostituirle con oggetti controllati
Stub
◦ Non hanno logica interna
◦ Comportamento sempre uguale
◦ Non si effettuano verifiche sugli stub
◦ Es. finta risorsa web
Stub e Mock
Mock
◦ Programmabile
Quando metodo riceve X Restituisci Y
Lancia eccezione
…
◦ Verifiche sui mock
Numero di chiamate ad un metodo
Parametro passato ad un metodo
…
Mocking library: Mockito
Mock lifecycle:
◦ Crea mock a partire da interfaccia
◦ Programma comportamento atteso
◦ Utilizzo indiretto (da parte del SUT*)
◦ Verifica dell’utilizzo
SUT = System Under Test, classe sottoposta a verifica
Mockito: esempio
MovieFinder finder = mock(MovieFinder.class) when(finder.findAll()).thenReturn(allMovies); MovieLister lister = new MovieLister(finder); Lister.moviesDirectedBy(“Martin Scorsese”); verify(finder).findAll(); // verifica la chiamata
ESEMPIO…
Mockito: possibilità MovieFinder finder = mock(MovieFinder.class) when(finder.findAll()).___________ .thenReturn(allMovies); .thenReturn(none, all); .thenThrows(new RuntimeException()); .then( callback ); MovieLister lister = mock(MovieLister.class) when(lister.moviesDirectedBy(_____)).then(…); “Martin Scorsese” anyString() any()
Mockito: spies
List list = new ArrayList(); List spy = spy(list); // calls real method! spy.add(“one”); spy.add(“two”); // verify verify(spy).add("one");
Utile per testare codice esistente
Test di risorse web
Esempio con Jetty (OnlineMovieFinder)
OnlineMovieFinder Risorsa web
Tester
Jetty Server
Servlet Stub
ESEMPIO…
Test Driven Development
Test first!
TDD mantra:
◦ RED
◦ GREEN
◦ REFACTOR
Test Driven Development
Ho un metodo calcolaX(a, b)
Ho bisogno di un test che verifica TUTTO!
Dati a, b vorrei ottenere X
Se a < 0, vorrei avere un errore
Se b == 0, vorrei…
1° test
2° test
3° test
Test Driven Development
What is the common, expected case?
What are some possible unusual cases?
How many external dependencies do I have?
What system failures could I reasonably encounter here?
http://www.codinghorror.com/blog/2005/04/good-test-bad-test.html
Costringe ad affrontare domande scomode
Costringe a pensare prima di scrivere
The real value of unit testing is that it forces you to stop and think about testing.