Testing
“Il testing verifica la presenza di errori, non la loro assenza.”
Testing e definizioni
Perché testing? Per verificare la correttezza del software rispetto la specifica. La verifica puó quindi cogliere se il prodotto é corretto o meno, non i reali bisogni dell’utente. Quest’ultima attivitá é legata alla validazione di un programma.
Diverse definizioni:
-
Verifica statica automatica: analisi statica del compilatore/software su un semilavorato espresso in linguaggio formale. Permette di rilevare ad esempio variabili mai utilizzate o semplici ottimizzazioni, ma mai problemi di prestazioni.
-
Testing (analisi dinamica): in generale non é possibile testare in maniera esaustiva un software a causa della possibile infinitá di casistiche.
-
Code inspection (analisi statica): in genere effettuata da un umano rileggendo altro codice.
-
Test di regressione: quando si controlla che una nuova versione non faccia regredire nessun aspetto del programma (non voglio che nella versione 2.0 non ci siano caratteristiche soddisfatte dalla versione 1.9).
Durante fasi di testing si possono utilizzare stubs e drivers :
- stub: un’interfaccia che serve a emulare un modulo ancora in fase di implementazione e a sostituirlo quindi, per permettere lo sviluppo parallelo di piú moduli indipendenti
- driver: costruzione di un oggetto che invoca l’oggetto da testare. Il contrario di stub sostanzialmente. Utilizzato molto in un approccio bottom-up , quando partendo dall’astrazione piú a basso livello sará necessario costruire tutti gli oggetti chiamanti, dovendo testare gli oggetti chiamati.
Durante il test si ragiona per casi limite. Quasi sempre negli esercizi avremo moduli white-box, cioé di cui conosciamo l’implementazione a differenza dei moduli black-box .
Possibili coperture da valutare sono:
- copertura di tutte le istruzioni (statements coverage)
- copertura tutte le decisioni (edge coverage)
- copertura di tutti i cammini (path coverage)
Statements Coverage (istruzioni)
Ogni istruzione all’interno del software deve essere eseguita almeno una volta.
Edge Coverage (decisioni)
Il criterio di copertura delle decisioni (decision coverage, edge coverage o branch coverage) esamina ogni ramificazione all’interno del codice. Equivale a testare ogni condizione di salto (if, while, … ) sia per valori di verità che di falsità. Per completare questo criterio risulta necessario costruire un insieme di test tali per cui ciascuna decisione venga percorsa per i valori di verità e falsità e che ciascuna istruzione al suo interno sia eseguita almeno una volta.
Path Coverage
Si garantisce che ogni condizione assuma il valore di verità e falsità almeno una volta. Questo significa che oltre a garantire la presa/rifiuto del branch, si garantisce che esso viene preso in tutti i modi possibili. Per far ciò ogni decisione deve essere scomposta in condizioni elementari, e far in modo che ciascuna condizione sia vera e falsa.
Osservazioni Path vs Edge
Naturalmente coprire tutte le decisioni non garantisce la copertura della condizioni. Anche il viceversa, tuttavia, non vale in generale: si tratta di casi ”patologici”, in cui il valore di veritá di una condizione non cambia anche assegnando tutti i possibili di valori di verità alle condizioni elementari di cui è composta. Esempi tipici sono formule booleane sempre false o sempre vere. Si ricorda che anche la condizione dentro il for deve essere controllata!