Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...
Py a1 python-unit_testing
1.
2. Introduzione
Il Python mette a disposizione un modulo per
lo Unit Testing di moduli
Modulo unittest
Altrimenti chiamato PyUnit (in omaggio a Junit)
pydoc unittest
Caratteristiche di unittest
Automazione delle procedure di test
Codice di setup/teardown (condivisibile)
Aggregazione di test in suite (collections)
Linguaggi dinamici – A.A. 2009/2010
2
3. Nomenclatura
Test fixture: è un insieme di operazioni/risorse
propedeutiche per un test
Creazione di DB di prova, instanziazione di un
Web server, creazione lista di numeri casuali
Test case: è l'unità di test più piccola possibile
Si controlla se, in corrispondenza ad input ben
specifici, la risposta del software è conforme
Test suite: è una collezione di test case e/o di
test suite
Test runner: orchestra l'esecuzione dei test e
fornisce un report (testuale, grafico) all'utente
Linguaggi dinamici – A.A. 2009/2010
3
4. Architettura ad oggetti
Le entità ora descritte sono implementate
tramite opportune classi
Test fixture, Test case TestCase
Test suite TestSuite
Test Running TextTestRunner, TestLoader
Linguaggi dinamici – A.A. 2009/2010
4
5. La classe TestCase
La classe TestCase rappresenta il singolo
contenitore di test
Un test è una sottoclasse di TestCase che
contiene un metodo per ciascun test che si
vuole effettuare
I nomi delle funzioni di test sono arbitrari
Se si utilizza il prefisso “test” è possibile
identificare tali metodi automaticamente nel
processo di creazione delle suite
Linguaggi dinamici – A.A. 2009/2010
5
6. Le asserzioni
Ciascun test esegue operazioni su risorse
specifiche dell'applicazione e verifica se il
risultato è quello atteso oppure no
Lo strumento utilizzato per le verifiche è quello
delle asserzioni
Si verifica se una data proprietà, risultato di una
invocazione ad un metodo, è vera
Per ciascuna asserzione, viene registrato il
successo o il fallimento della stessa
Al termine del test, un report presenta il
conteggio delle asserzioni riuscite e fallite
Linguaggi dinamici – A.A. 2009/2010
6
7. Le asserzioni
Alcune asserzioni (msg: messaggio di
riconoscimento del test nella reportistica)
assertTrue(expr, msg): verifica che expr == True
assertFalse(expr, msg): verifica che expr ==
False
assertEqual(first, second, msg): verifica che
first == second
failIf(expr, msg): verifica che expr == False
failUnless(expr, msg): verifica che expr == True
failIfEqual(first, second, msg): verifica che
first != second
failUnlessEqual(expr, msg): verif first==second
Linguaggi dinamici – A.A. 2009/2010
7
8. Le asserzioni
Alcune asserzioni (msg: messaggio di
riconoscimento del test)
assertAlmostEqual(first, second, places, msg):
verifica che first ~ second alla places cifra
decimale
failIfAlmostEqual(first, second, places, msg): è
l'inverso di assertAlmostEqual()
assertRaises(exception, callable, args): verifica
che per l'invocazione di callable con argomenti
args sia sollevata una eccezione
Linguaggi dinamici – A.A. 2009/2010
8
9. ESEMPI:
simplistictest.py
Esecuzione di un test testtruth.py
testequal.py
testalmostequal.py
Per eseguire un test case, occorre: testexception.py
Importare il modulo relativo alla funzionalità che
si intende verificare
importare il modulo unittest
creare una sottoclasse la classe TestCase che
implementa il test
invocare il metodo main() del modulo unittest
Il codice di invocazione di main() può essere
integrato nel file contenente la classe TestCase
if __name__ == '__main__':
unittest.main()
Linguaggi dinamici – A.A. 2009/2010
9
10. Risultato di un test
Ciascun test ha tre possibili risultati:
ok: il test ha avuto esito positivo
FAIL: il test non ha avuto esito positivo e
solleva una eccezione AssertionError (una
asserzione non è vera)
ERROR: il test non ha avuto esito positivo e
solleva una eccezione diversa da AssertionError
(c'è un errore nel codice)
Linguaggi dinamici – A.A. 2009/2010
10
11. ESEMPI:
outcometest.py
Risultato di un test
Si possono forzare ok, FAIL, ERROR nei test?
ok: si scrive un test che ritorna semplicemente
FAIL: si scrive un test che fallisce sempre
ERROR: si scrive un test che sollevi una
qualunque eccezione diversa da AssertionError
Linguaggi dinamici – A.A. 2009/2010
11
12. ESEMPI:
testfixture.pm
Test fixture randomtest.py
Come già osservato in precedenza, un test ha
spesso bisogno di operare su risorse (oggetti)
che devono pertanto essere preallocati
La classe TestCase fornisce un meccanismo
per l'invocazione automatica dei metodi di
allocazione e rilascio delle risorse
setUp(): allocazione di risorse (invocata prima
del primo test)
tearDown(): rilascio di risorse (invocata dopo
l'ultimo test)
Per poter usare le text fixture, è sufficiente
ridefinire tali due metodi nella classe di test
Linguaggi dinamici – A.A. 2009/2010
12
13. Esecuzione suite di test
Per eseguire una suite di test, è necessario
svolgere alcuni passi
Passo 1: si definisce una istanza di sottoclasse
di TestCase per ciascun metodo che si intende
eseguire nella suite
Voglio eseguire il metodo testarea() del
TestCase testRettangolo; istanzio un oggetto di
tipo testRettangolo, passando come argomento
la stringa “testarea”
t = testRettangolo(“testarea”)
La stringa “testarea” viene utilizzata dalla
superclasse TestCase per capire cosa eseguire
Linguaggi dinamici – A.A. 2009/2010
13
14. Esecuzione suite di test
Per eseguire una suite di test, è necessario
svolgere alcuni passi
Passo 2: creo un oggetto di tipo TestSuite
ts = TestSuite()
Passo 3: aggiungo all'oggetto TestSuite tutte le
istanze di tipo TestCase definite nel passo 1
ts.addTest(t)
Linguaggi dinamici – A.A. 2009/2010
14
15. Esecuzione suite di test
Per eseguire una suite di test, è necessario
svolgere alcuni passi
Passo 4: si sceglie il tipo di report che si vuole
ottenere (testuale, grafico, Web) e si istanzia
un oggetto della relativa classe
Il report di default è quello testuale, che
corrisponde alla classe TextTestRunner
r = TextTestRunner(sys.stdout, verbosity = 2)
sys.stdout: è lo stream di output del report
verbosity: è il livello di verbosità dell'output
Altra opzione: HTMLTestRunner, report HTML
(pacchetto scaricabile)
Linguaggi dinamici – A.A. 2009/2010
15
16. ESEMPI:
testsuite1
Esecuzione suite di test
Per eseguire una suite di test, è necessario
svolgere alcuni passi
Passo 5: Si esegue il metodo run() dell'oggetto
di tipo TestRunner, passando l'oggetto di tipo
TestSuite come parametro
res = r.run(ts)
res conterrà un oggetto TestResult con il
resoconto dei test effettuati
Linguaggi dinamici – A.A. 2009/2010
16
17. ESEMPI:
testsuite2
La classe TestLoader
Costruire a mano la suite di test è un compito
tedioso e soggetto ad errori
E' possibile automatizzare tale procedura
tramite l'utilizzo della classe TestLoader
La classe TestLoader esporta un metodo
loadTestsFromTestCase() che:
accetta in ingresso un nome di classe di test
restituisce un oggetto di tipo TestSuite
contenente tutti i metodi della classe di test
Linguaggi dinamici – A.A. 2009/2010
17
18. ESEMPI:
testsuite3
La classe TestLoader
All'interno del file di suite, si definisce tramite
TestLoader() un oggetto di tipo TestSuite per
ciascun modulo che si intende verificare
All'interno del file di suite, si crea un ulteriore
oggetto di tipo TestSuite che rappresenta il
test finale e contiene le suite definite nel punto
precedente
E' possibile rifattorizzare ulteriormente i test
definendo in ciascuna classe di test un metodo
(ad es. suite()) che restituisce l'oggetto di tipo
TestSuite
Linguaggi dinamici – A.A. 2009/2010
18
19. ESEMPI:
testsuite4
Organizzazione delle directory
All'interno di un progetto, il codice
dell'applicazione e dei test è separato in due
directory distinte (src e test)
Occorre specificare il percorso dei moduli
all'interno della directory di test
Si usa la variabile di ambiente shell
PYTHONPATH
PYTHONPATH=/path/to/app/modules ./suite.py
Linguaggi dinamici – A.A. 2009/2010
19