Agent and Object Technology LabDipartimento di Ingegneria dell’Informazione
Università degli Studi di Parma
AOTAOTLABLAB
Ingegneria del software A
Testing
Michele Tomaiuolo
2
AOTAOTLABLAB Qualità interne ed esterne
Le qualità su cui si basa la valutazione di un sistemasoftware possono essere: Interne, riguardano le caratteristiche legate allo sviluppo del
software e non sono visibili agli utentiEsterne, riguardano le funzionalità fornite dal sistema e sono visibili
agli utenti
Le categorie sono legate, non è possibile ottenerequalità esterne se il sistema non gode di qualità interne
3
AOTAOTLABLAB Qualità del prodotto e del processo
È anche possibile valutare un sistema secondo qualitàRelative al prodotto, riguardano le caratteristiche stesse del sistema
e sono sempre valutabiliRelative al processo, riguardano i metodi utilizzati durante lo
sviluppo del software
Le categorie sono legate, non è possibile ottenerequalità del prodotto se il sistema non gode di qualità delprocessoProduct quality is process quality
4
AOTAOTLABLAB Qualità esterne
Correttezza: il sistema rispetta le specificheAffidabilità (dependability): l’utente può dipendere dal
sistemaRobustezza: il sistema si comporta in modo ragionevole
anche in circostanze non previste dalle specificheEfficienza: usa bene le risorse di calcoloScalabilità: migliori prestazioni con più risorseSicurezza: authentication, authorization, accountingFacilità d’uso: un sistema è facile da usare se
l’interfaccia che presenta all’utente gli permette diesprimersi in modo naturale
5
AOTAOTLABLAB Valutazione delle qualità
Valutazione sulla base delle specificheCorrettezza e affidabilitàRobustezza: riguarda tutti i casi non trattati dalle specifiche
Valutazione dei committentiCorrettezza e facilità d’uso
Valutazione degli sviluppatoriRobustezza ed efficienza
6
AOTAOTLABLAB Qualità interne
Verificabilità: sistema basato su modello formaleRiusabilità: parti usabili per costruire nuovi sistemiManutenibilità
Riparabilità: facilitata la ricerca degli erroriEvolvibilità: aggiungere nuove funzionalità al sistemaAdattabilità: rispetto a cambiamenti del dominio applicativo
Interoperabilità: capacità di co-operare con altri sistemi,anche di altri produttori
Portabilità: può funzionare su più piattaforme hw/swComprensibilità: codice leggibile, documentazioneModularità: interazione tra componenti coesi
7
AOTAOTLABLAB Qualità del processo
Produttività, misura l’efficienza del processo nei terminidella velocità di consegna del sistema
Tempestività, misura la capacità del processo di valutaree rispettare i tempi di consegna del sistema
Trasparenza, un processo di produzione è trasparentese permette di capire il suo stato e di controllarne i passi
Agilità, misura la capacità del processo di consentire laproduzione in tempi ridotti (ridotto time-to-market)
8
AOTAOTLABLAB Costi del software
I costi del software sono spesso predominanti nei costi diun sistema Il costo del software in un PC spesso è maggiore di quello
dell’intero hardware
Il costo del software è principalmente nel mantenimentopiuttosto che nello sviluppo
Uno degli obiettivi principali dell’ingegneria del software èottenere un sviluppo cost-effective prevenendo perquanto possibile i costi di manutenzione
9
AOTAOTLABLAB Costo diretti
Costo delle risorse per lo sviluppo (costi diretti)Costo del personale sviluppatore, spesso predominante sugli altriCosto del personale di supportoCosto delle risorse di sviluppoMateriali di consumoAltri costi generali della struttura
10
AOTAOTLABLAB Costi indiretti
Altri costi, più aleatori (costi indiretti)Capacità, motivazione e coordinamento del personaleComplessità del sistema da realizzareStabilità dei requisitiCaratteristiche dell’ambiente di sviluppo
Costo di manutenzione ed evoluzione
11
AOTAOTLABLAB Evoluzione di un sistema software
Il software deve evolvere perché:Non sono stati colti correttamente i requisiti I requisiti non sono inizialmente notiCambiano le condizioni operative…
L’evoluzione è ineliminabile per gran parte delle tipologiedi sistemi, anche se i requisiti iniziali sono corretti ecompleti
12
AOTAOTLABLAB Manutenzione
Manutenzione è il processo di modifica di un sistemadopo il suo rilascio al fine di…Eliminare anomalie (manutenzione correttiva)Migliorare le prestazioni o altri attributi di qualità (manutenzione
perfettiva)Adattare a mutamenti dell’ambiente (manutenzione adattativa)
Costi della manutenzione:Spesso maggiori del 50% del costo totale del software75% (fonte Hewlett-Packard)70% (fonte Dipartimento della Difesa degli Stati Uniti)
Manutenzione correttiva: 20%Manutenzione perfettiva: 60%Manutenzione adattativa: 20%
13
AOTAOTLABLAB Dati sulla manutenzione
Esperienza di Hewlett-PackardLa maggior parte degli errori potrebbe essere scoperta mediante
tecniche sistematiche di revisione di progetto I moduli con maggior complessità del flusso di controllo hanno
maggiore probabilità di contenere errori
Alcuni datiSu 10 difetti scoperti durante il test, 1 si propaga nella
manutenzioneEliminare i difetti costa, in tempo, 4-10 volte per sistemi grossi e
maturi rispetto a piccoli e ancora in sviluppo Il costo di rimozione degli errori aumenta con il ritardo rispetto al
quale gli errori sono introdotti
14
AOTAOTLABLAB Problemi più attuali
Gestire sistemi vecchi ma non sostituibili (legacy system)Necessità di manutenzione adattativaProblemi dovuti alla tecnologia obsoleta
Gestire l’eterogeneità dei sistemi I sistemi sono sempre distribuiti e sono composti da una grande
varietà di sistemi hardware e software
Riduzione dei tempi di consegnaC’è una sempre maggiore pressione per ottenere tempi di
consegna brevi
15
AOTAOTLABLAB Verifica e validazione
La verifica e la validazione servono per mostrare che ilsistema È conforme alle specifiche Incontra i requisiti dell’utente
Comprende revisione e testing del sistema
Il testing di un sistema richiede di eseguire il sistema sucasi di test (test case) derivati dalle specifiche
16
AOTAOTLABLAB Testing
Le operazioni di testingpossono individuare la presenza di errori nel software
ma non ne possono dimostrare la correttezza-- E. Dijkstra
A cosa serve il testingVerificare il comportamento del sistema in un insieme di casi
sufficientemente ampio da rendere plausibile che il suocomportamento sia analogo anche nelle restanti situazioni
Le operazioni di testing si suddividono in:Testing in the small, riguardano moduli singoliTesting in the large, riguardano il sistema nella sua globalità
17
AOTAOTLABLAB Processo di Testing
Sub-systemtesting
Moduletesting
Unittesting
Systemtesting
Acceptancetesting
Componenttesting
Integration testing Usertesting
18
AOTAOTLABLAB Fasi di Testing (1/2)
Unit testingOgni singolo componente
Module testingOgni modulo, insieme di componenti interdipendenti
Sub-system testing Integrazione tra moduli in sotto-sistemi per individuare problemi
nelle interfacce tra i moduli
System testingSistema nel suo complesso, eventuali proprietà emergenti del
sistema
Acceptance testingCon i committenti per verificare l’accettabilità del sistema
19
AOTAOTLABLAB Fasi di Testing (2/2)
Requirementsspecification
Systemspecification
Systemdesign
Detaileddesign
Module andunit codeand tess
Sub-systemintegrationtest plan
Systemintegrationtest plan
Acceptancetest plan
Service Acceptancetest
Systemintegration test
Sub-systemintegration test
20
AOTAOTLABLAB Statement test
Valuta il corretto funzionamento di una porzione delcodiceAnalizzando il suo output in relazione ad input significativi
Verifica di copertura dei programmi (statement test)Un errore non può essere scoperto se la parte di codice che lo
contiene non viene eseguita almeno una voltaCriterio: selezionare un insieme di test T tali che, a seguito
dell’esecuzione del programma P su tutti i casi di T, ogni istruzioneelementare di P venga eseguita almeno una volta
Può essere eseguito solo conoscendo la struttura interna dellaporzione di codice (white-box testing)
21
AOTAOTLABLAB Branch test
Verifica di copertura delle decisioni (branch test)
Per ogni condizione presente nel codice è utilizzato un test cheproduca risultato vero e falso
Criterio: selezionare un insieme di test T tali che, a seguitodell’esecuzione del programma P su tutti i casi di T, ogni arco delgrafo di controllo di P sia attraversato almeno una volta
Può essere eseguito solo conoscendo la struttura interna dellaporzione di codice
22
AOTAOTLABLAB Branch and condition test
Verifica di copertura delle decisioni e delle condizioni
Per ogni porzione di condizione composta presente nel codice, siautilizzato un test che produca il risultato vero e falso
Criterio: selezionare un insieme di test T tali che, a seguitodell’esecuzione del programma P su tutti i casi di T, ogni arco delgrafo di controllo di P sia attraversato e tutti i possibili valori dellecondizioni composte siano valutati almeno una volta
Produce un’analisi più approfondita rispetto al criterio di coperturadelle decisioni
Può essere eseguito solo conoscendo la struttura interna dellaporzione di codice
23
AOTAOTLABLAB Testing in the large
Il white-box testing è impossibile per sistemi di grandidimensioni
Il sistema è visto come una scatola nera (black-boxtesting) e si vanno a verificare le corrispondenze di inpute output
L’insieme di test da utilizzare viene selezionato sullabase delle specifiche
24
AOTAOTLABLAB Esempio: fatture
Problema: il sistema riceve come input una fattura dicui è nota la struttura dettagliataLa fattura deve essere inserita in un archivio ordinato per dataSe esistono altre fatture con la stessa data fa fede l’ordine di arrivo
È inoltre necessario verificare che: Il cliente sia già stato inserito in archivio eVi sia corrispondenza tra la data di inserimento del cliente e quella
della fattura, …
Test set:1. Fattura con data odierna2. Fattura con data passata e per la quale esistono altre fatture3. Fattura con data passata e per la quale non esistono altre fatture4. Fattura il cui cliente non è stato inserito5. …
25
AOTAOTLABLAB Ispezione del software
Analisi del codice per capirne le caratteristiche e lefunzionalitàPuò essere effettuata sul codice oppure sullo pseudocodicePermette la verifica unitaria di un insieme di condizioniÈ soggetta agli errori di colui che la effettuaSi basa su un modello della realtà e non su dati reali
I due principali approcciCode walk-throughCode inspection
26
AOTAOTLABLAB Code walk-through
Analisi informale eseguita da un team di persone1. Opportuna selezione di porzioni del codice e valori di input2. Simulazione su carta del comportamento del sistema
Il numero di persone coinvolte deve essere ridotto Al fine di aumentare il clima di cooperazione all’analisi non
devono partecipare i manager
Il progettista deve fornire in anticipo documentazione del codice L’analisi non deve durare più di alcune ore L’analisi deve essere indirizzata solamente alla ricerca dei
problemi e non alla loro soluzione
27
AOTAOTLABLAB Code inspection
Analisi eseguita da un team di persone e organizzatacome nel caso del code walk-throughMira a ricercare classi specifiche di errori Il codice viene esaminato controllando soltanto la presenza di una
particolare categoria di errore, piuttosto che simulando unagenerica esecuzione
Le classi di errori che vengono solitamente ricercate conquesta tecnica sonoUso di variabili non inizializzateLoop infinitiLetture di porzioni di memoria non allocataRilascio improprio della memoria
28
AOTAOTLABLAB Program testing
Program testing is the process of executing a programwith the intent of finding errors
-- Glen Myers, “The art of Software Testing”
Buon test: buone probabilità di trovare erroriNon può dimostrare l’assenza di erroriPuò solo mostrare la presenza di errori
Ad alto consumo di risorse e tempoNon è insolito dedicare al testing il 40% degli sforzi
complessivi di un progetto
29
AOTAOTLABLAB Classificazione dei test
Tipi di testWhite boxBlack box test
Livelli di testUnit test Integration testSystem test
Ripetizione di testRegression test
30
AOTAOTLABLAB Testabilità
Qualità del software che influiscono sulla capacità dirilevare errori
Osservabilità – Risultato di un test raggiungibile e visibileControllabilità – Ingressi e stato di un programma
devono essere controllabili prima di eseguire un testDecomponibilità – Il programma deve essere diviso in
parti che possano essere testate individualmenteComprensibilità – L’intenzione del programmatore, sul
comportamento corretto del programma, deve esseredisponibile per il tester
Progettazione per testabilità
31
AOTAOTLABLAB Test utopia
In un mondo ideale, tutti i possibili percorsi di esecuzionedi un programma dovrebbero essere testati
Test totale di un programma: esecuzione di tutte lepossibili combinazioni di comandi ed espressioni relativealle strutture di controlloAnche in piccoli programmi, il numero di percorsi in un test totale è
molto ampio In molti programmi, non è noto il limite di percorsi di un test totaleNel mondo reale, bisogna selezionare il sottinsieme di percorsi del
test totale con maggiore probabilità di rilevare errori nel programma
32
AOTAOTLABLAB Prove matematiche
Una dimostrazione matematica di un programma è unaalternativa (principalmente accademica) al testing
Le post condizioni devono essere verificate dato cheLe precondizioni siano verificate Il programma termina
Si basa suAnnotazione del programma con asserzioni matematiche che
riflettono il comportamento attesi dal programmaProprietà che valgono per i vari costrutti del programmaLe dimostrazioni eseguite a mano avranno probabilmente più errori
che il programma stessoMaggiore fiducia solo da dimostrazioni automatiche
33
AOTAOTLABLAB Testing white box
Usa le strutture di controllo di un programma perderivare i test caseScopo: garantire che tutti i comandi e le espressioni di un
programma siano eseguiti almeno una volta
DesiderataTutti i percorsi indipendenti di una unità del programma siano
eseguiti almeno una voltaTutte le derivazioni logiche siano esercitateTutti i cicli e le strutture dati siano esercitati ai loro limiti
34
AOTAOTLABLAB Basic path testing
Tecnica di testing “white box”, che aiuta a scegliere uninsieme minimo di percorsi in un programma checoprono tutte le istruzioni e condizioni
Un percorso in una unità di programma è una sequenzadi comandi e condizioni, dall’inizio alla fine
Cammino indipendente: aggiunge almeno una nuovaistruzione o condizione rispetto ai cammini indipendentigià identificati
Approccio complessivo1. Tracciare un diagramma di flusso della unità2. Astrarre il diagramma in un grafo3. Trovare la complessità ciclomatica (diciamo n) – metrica di test4. Trovare n casi di test che seguono ciascun cammino indipendente
35
AOTAOTLABLAB Complessità ciclomatica
public static void P(){// Entrywhile(A) {X;if (B) {
if(C)Y;
elseZ;
// p} else {
V; W;}// q
}// Exit: r
}}
37
AOTAOTLABLAB Grafo di flusso
Piccola astrazione rispetto ad un diagramma di flusso
A, rA, X, B, C, Y, p, q, A, rA, X, B, C, Z, p, q, A, rA, X, B, V, W, q, A, r
39
AOTAOTLABLAB Metrica e casi di test
Calcolare la metrica e trovare i casi di test sulla basedella complessità
Complassità ciclomatica: determinata sul grafo,usando semplici concetti della teoria dei grafiNumero di regioni del grafo di flusso, oNumero di nodi predicato + 1
Costruire un caso di test per ogni camminoindipendenteIl caso di test dovrebbe seguire il controllo del percorso
40
AOTAOTLABLAB Esempio: GCD
int gcd(int i, int j) {int small, large, remainder;if (i <= j)small = i;
elsesmall = j;
if (i <= j)large = j;
elselarge = i;
while (small > 0) {remainder = large % small; large = small; small = remainder;
}return large;
}void main() {int i, j;printf("Enter two positive integers: "); scanf("%d %d", &i, &j);printf("GCD of %d and %d is %d\n\n", i, j, gcd(i,j));
}
41
AOTAOTLABLAB Complessità di GCD
La complessità ciclomatica di GCD è 4In generale, la complessità ciclomatica è un limite
superiore per il numero di test case necessariNella funzione GCD, è possibile coprire tutte le righe di
codice con due test case
Si noti che in gcd le condizioni delle due strutture dicontrollo sono accoppiateCattiva programmazione!Potrebbe essere impossibile trovare dat che esercitino tutti I
cammini indipendenti
42
AOTAOTLABLAB Black box testing
Usa l’interfaccia di una unità di programma per costruireI test case
Lo scopo è dimostrare che viene prodotta l’uscitacorretta per input validi – in relazione ai requisitifunzionali
DesiderataTrovare gli errori funzionali: otteniamo i risultati attesi per dati input
di un metodo?Trovare errori di interfaccia: i dati sono passati correttamente tra i
metodi?Trovare errori di efficienza: il metodo è abbastanza veloce?
43
AOTAOTLABLAB Input per un test black box
Non è realistico – da un punto di vista combinatorio –testare un programma su tutti i possibili ingressi
Questione centrale: scelta valori d’ingressoPartizionamento degli ingressi in classi di equivalenzaSi ipotizza che sia sufficiente testare l’unità di programma su un
solo caso per classe
Si includono i casi limiteTipo collezioni vuote o piene
Si includono uno o più casi di input non validoCon controllo sui tipi e precondizioni lo spazio è limitato
44
AOTAOTLABLAB Partizioni d’equivalenza
// Exchange element i and j in tablepublic void swapElements(T[] table, int i, int j) {
. . .}
Partizioni d’equivalenza – tutte le combinazioni di:Table
Vuota, o non vuota i, j
Almeno uno tra i e j fuori dai limitiSia i che j dentro i limiti: i < j, i > j, i = j
L’uso di controllo dei tipi e controllo dei limiti riduce ilnumero di casi di test
45
AOTAOTLABLAB Partizioni d’equivalenza
// Find the largest element in table in between from and to.// Precondition: 0 <= from <= to <= table.Count-1public int findMaxIndex(T[] table, int from, int to) {
. . .}
Precondizioni ben scelte riducono il numbero di test
Partizioni d’equivalenza – tutte le combinazioni di:Table
VuotaElemento maggiore primo, ultimo o a metà in tableTutti elementi uguali
from e to from e to ai limiti della tabella from = to, from = to - 1, oppure lontani tra loro
46
AOTAOTLABLAB Regression testing
Lo scopo del regression test è trovare errori diregressioneErrori in un programma che prima era corretto, ed è stato modificato
di recenteUn errore di regressione è un errore che non c’era
Dopo la modifica di una perte P nel programma QTestare che la parte P funzioni correttamenteTestare che l’intero programma Q non sia stato danneggiato dalla
modifica
47
AOTAOTLABLAB Annotazioni
Forniscono dati su un programmaNon sono parte delle istruzioni del programma stesso
Usi: Informazioni per il compilatore - Per rilevare errori o sopprimere
warningElaborazione durante la compilazione o il deployment – Gli
strumenti software possono generare code, file XML ecc.Elaborazione durante l’esecuzione – Alcune annotazioni sono
disponibili a runtime
Le annotazioni possono essere applicate a classi, campi,metodi e altri elementi del programma
48
AOTAOTLABLAB Sintassi
All’inizio di una riga, (per convenzione su una rigapropria), può includere elementi con nome
@Author(name = "Benjamin Franklin",date = "3/27/2003“
)class MyClass() { }
@SuppressWarnings(value = "unchecked")void myMethod() { }
@SuppressWarnings("unchecked") // name omitted, just one elementnamed "value“
void myMethod() { }
@Overridevoid mySuperMethod() { }
49
AOTAOTLABLAB Documentazione
// metadata in commentspublic class Generation3List extends Generation2List {// Author: John Doe// Date: 3/17/2002// Current revision: 6// Last modified: 4/12/2004// By: Jane Doe// Reviewers: Alice, Bill, Cindy
// class code goes here}
// metadata in annotations@interface ClassPreamble {String author();String date();int currentRevision() default 1;String lastModified() default "N/A";String lastModifiedBy() default "N/A";String[] reviewers(); // Note use of array
}
50
AOTAOTLABLAB Documentazione
Dopo aver definito un tipo d’annotazione, si può usarefornendo i valori richiesti
@Retention(RetentionPolicy.RUNTIME) // keep info for runtime@Documented // add metadata to javadoc documentation@ClassPreamble (author = "John Doe",date = "3/17/2002",currentRevision = 6,lastModified = "4/12/2004",lastModifiedBy = "Jane Doe“reviewers = {"Alice", "Bob", "Cindy"} // Note array notation
)public class Generation3List extends Generation2List {// class code goes here
}
51
AOTAOTLABLAB Annotazioni per il compilatore
Tre annotazioni predefinite nelle specifiche dellinguaggio
@Deprecated Indica elementi non più in uso Il compoilatore genera un warning se un programma lo usaViene documentato in Javadoc
@Override Informa il compilatore che si sovrascrive un elemento della
superclasse
@SuppressWarnings Il compilatore non genera warningdeprecation:unchecked: uso di codice senza generics
52
AOTAOTLABLAB Elaborazione delle annotazioni
Possibile scrivere processori di annotazioni, per leggereun programma e agire a seconda delle annotazioni
Generazione automatica di codice ripetitivo
Occorre implementare AnnotationProcessor
Java 5: apt (annotation processing tool)Java 6: funzionalità inclusa nel compilatore javac
53
AOTAOTLABLAB JUnit
Caratteristiche principaliNovità delle ultime versioniTest parametrici, di eccezione e temporizzatiFixture flessibiliRaggruppamento ad esclusione di testTesting con Eclipse e Ant
54
AOTAOTLABLAB Il vecchio JUnit
Prima dell’aggiunta delle annotazioni in Java 5, ilframework JUnit (ver<4) aveva stabilito due convenzioniessenziali per il suo funzionamento
1. Ogni metodo scritto per funzionare come un test logicocominciava con la parola “test” Se un metodo cominciava così, es. testUserCreate, veniva
incluso nel processo di test (fixture eseguite prima e dopo)
2. Una classe veniva riconosciuta da JUnit comecontenitore di test solo se estendeva TestCase
Un test che violava una delle due convenzioni, nonveniva eseguito
55
AOTAOTLABLAB Esempio JUnit (ver<4)
import java.util.regex.Matcher;import java.util.regex.Pattern;import junit.framework.TestCase;
public class RegexTest extends TestCase {private String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
public void testZipCode() throws Exception {Pattern pattern = Pattern.compile(zipRegEx);Matcher m = this.pattern.matcher("12345");boolean isValid = m.matches();assertTrue("Zip code wasn’t validated", isValid);
}}
56
AOTAOTLABLAB JUnit 4
JUnit 4 usa le annotazioni di Java 5 per eliminarecompletamente entrambe le convenzioni
1. La gerarchia di classi non è più richiesta2. Ogni metodo che si vuole far fuzionare come test deve
essere annotato come @Test
Static import Gli static import di Java 5 permettono di usare più facilmente i
metodi della classe Assert, es. assertFalse I test non estendono più TestCase, nè alcuna classe
57
AOTAOTLABLAB Esempio JUnit 4
import java.util.regex.Matcher;import java.util.regex.Pattern;import org.junit.Test;import static org.junit.Assert.assertTrue;
public class RegexTest {private String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
@Testpublic void verifyGoodZipCode() throws Exception {
Pattern pattern = Pattern.compile(zipRegEx);Matcher m = this.pattern.matcher("22101");boolean isValid = m.matches();assertTrue("Zip code wasn’t validated", isValid);
}}
58
AOTAOTLABLAB Vantaggio delle annotazioni
Le annotazioni documentano chiaramente ciò che unmetodo dovrebbe fare
Non richiedono di conoscere il modello interno delframework e tutte le convenzioni
In precedenza era richiesta familiarità con le convenzionidi JUnit anche solo per capire un test case
Inoltre le annotazioni aggiungono altre potenzialità alprocesso di test
59
AOTAOTLABLAB Test di eccezioni
Come nelle vecchie versioni di JUnit, bisogna specificareche i test possono lanciare ExceptionFunzionamento normale: se un test lancia una eccezione, il
framework marca il test come fallito
Caso particolare se si vuole testare il lancio di una certaeccezioneSull’annotazione @Test si può specificare il parametro expectedRappresenta il tipo di eccezione che dovrebbe venir lanciata
L’esempio seguente mostra il test delle eccezioni primanella vecchia forma, e poi nella nuova, più chiara
60
AOTAOTLABLAB Esempio con eccezioni (ver<4)
import java.util.regex.Matcher;import java.util.regex.Pattern;import junit.framework.TestCase;
public class RegexTest extends TestCase {private String zipRegex = "^\\d{5}([\\-]\\d{4})?$";private Pattern pattern;
protected void setUp() throws Exception {this.pattern = Pattern.compile(this.zipRegex);
}public void testZipCodeGroupException() throws Exception {Matcher m = this.pattern.matcher("12345-4321");boolean isValid = m.matches();try {m.group(2);fail("No exception was thrown");
} catch(IndexOutOfBoundsException e) { }}
}
61
AOTAOTLABLAB Aggiornamento test di eccezioni
Le vecchie versioni di JUnit richiedono un po’ di codiceper creare un semplice test sulle eccezioniAggiungere un blocco try/catch Invocare il fallimento del test se l’eccezione non viene catturata
Test di eccezioni in JUnit 4Differenza principale: si usa il nuovo paramento expectedÈ possibile aggiornare vecchi test aggiungendo l’eccezione alla
annotazione @Test
62
AOTAOTLABLAB Esempio con eccezioni
import java.util.regex.Matcher;import java.util.regex.Pattern;import org.junit.BeforeClass;import org.junit.Test;
public class RegexTest {private static String zipRegex = "^\\d{5}([\\-]\\d{4})?$";private static Pattern pattern;
@BeforeClasspublic static void setUpBeforeClass() throws Exception {pattern = Pattern.compile(zipRegex);
}@Test(expected=IndexOutOfBoundsException.class)public void verifyZipCodeGroupException() throws Exception {Matcher m = this.pattern.matcher("12345-4321");boolean isValid = m.matches();m.group(2);
}}
63
AOTAOTLABLAB Test temporizzati
In JUnit 4, un test può prendere un valore di timeoutcome parametro
Il valore di timeout rappresenta il massimo intervallo ditempo che l’esecuzione del test può impiegare
Se il tempo scade, il test fallisce
@Test(timeout=1)public void verifyFastZipCodeMatch() throws Exception {Pattern pattern = Pattern.compile("^\\d{5}([\\-]\\d{4})?$");Matcher m = pattern.matcher("12345");boolean isValid = m.matches();assertTrue("Pattern did not validate zip code", isValid);
}
64
AOTAOTLABLAB Test da ignorare
Prima di JUnit 4, ignorare un test sbagliato o incompletoera possibile in maniera piuttosto rozzaAlterare il nome del metodo in modo da infrangere la convenzioneSpesso si aggiungeva un underscore prima del nome del metodo,
per indicare che il test non era da eseguire
JUnit 4 ha introdotto la chiara annotazione @Ignore Indica al framework di ignorare un certo metodo di testSi può anche passare un messaggio per documentare la decisione
agli altri sviluppatori, altrimenti ignari dei motivi dell’esclusione
65
AOTAOTLABLAB Esempio di test da ignorare
@Ignore("this regular expression isn't complete yet")@Testpublic void verifyZipCodeMatch() throws Exception {Pattern pattern = Pattern.compile("^\\d{5}([\\-]\\d{4})");Matcher m = pattern.matcher("12345");boolean isValid = m.matches();assertTrue("Pattern did not validate zip code", isValid);
}
66
AOTAOTLABLAB Perché usare le fixture
Le fixture incoraggiano il riuso, definendo del codice chedeve essere eseguito prima o dopo i test
Nelle vecchie versioni di JUnit ciò era implicito, sia che lefixture fossero implementate o no
JUnit 4 ha reso le fixture esplicite con le annotazioniCodice fixture eseguito solo se necessarioSi può specificare che certe fixture siano eseguite prima o dopo di
certi test, codice riusato
67
AOTAOTLABLAB Esempi di fixture
Esempi Inizializzare una classe che verrà testata in modi diversiPopolare un database prima di eseguire test dipendenti dai dati
In ogni caso, l’uso delle fixture permette di gestire meglioi test, sfruttando logica comune
Le fixture tornano utili specialmente quando molti testusano in parte la stessa logica In caso di problemi, si può analizzare il codice di setup concentrato
in un solo punto, anzichè scorrere tutti i test
68
AOTAOTLABLAB Fixture inflessibili
Le vecchie versioni di JUnit impiegavano un modello difixture poco flessibileL’esecuzione di ogni test veniva preceduta dal metodo setUp e
seguita dal metodo tearDown
Svantaggio: metodi eseguiti più volte, una per ogni testdefinito
Nelle versioni precedenti di JUnit era possibilespecificare di eseguire una fixture solo una voltaSi istanziava un oggetto TestSetup nel metodo suiteMa era una operazione abbastanza scomodaManeggiare le fixture poteva portare più grattacapi che benefici
69
AOTAOTLABLAB Esempio di fixture di test (ver<4)
import . . .public class RegexTest extends TestCase {private Pattern pattern;protected void setUp() throws Exception {this.pattern = Pattern.compile("^\\d{5}([\\-]\\d{4})?$");
}public void testZipCodeGroup() throws Exception {Matcher m = this.pattern.matcher("12345-4321");assertEquals("group(1) didn't match", "-4321", m.group(1));
}public void testZipCodeGroupException() throws Exception {Matcher m = this.pattern.matcher("12345-4321");boolean isValid = m.matches();try{m.group(2);fail("No exception was thrown");
} catch(IndexOutOfBoundsException e) { }}
}
70
AOTAOTLABLAB Esempio di fixture di classe (ver<4)
import java.util.regex.*;import junit.extensions.TestSetup;import junit.framework.Test;import junit.framework.TestCase;import junit.framework.TestSuite;import junit.textui.TestRunner;
public class RegexTest extends TestCase {private static Pattern pattern;
public static Test suite() {TestSetup setup = new TestSetup(
new TestSuite(OneTimeRegexTest.class)) {protected void setUp() throws Exception {pattern = Pattern.compile("^\\d{5}([\\-]\\d{4})?$");
}};return setup;
}. . .
71
AOTAOTLABLAB Esempio di fixture di classe (ver<4)
. . .public void testZipCodeGroup() throws Exception {Matcher m = pattern.matcher("12345-4321");boolean isValid = m.matches();assertEquals("group(1) didn't match", "-4321", m.group(1));
}public void testZipCodeGroupException() throws Exception {Matcher m = pattern.matcher("12345-4321");boolean isValid = m.matches();try {m.group(2);fail("No exception was thrown");
} catch (IndexOutOfBoundsException e) { }}
}
72
AOTAOTLABLAB Fixture in JUnit 4
Nuovo e migliorato modello di fixture in JUnit 4 JUnit 4 usa le annotazioni per eliminare molto overhead relativo alle
fixturePermette di eseguire una fixture per ogni test, per una intera classe,
o non eseguirla affatto
2 annotazioni per le fixture di livello classeA livello di classe ci sono @BeforeClass e @AfterClassUtili per ottimizzazione (es. collegamento a DB)
2 annotazioni per le fixture di livello metodo (test)A livello di metodo (o test) ci sono @Before e @AfterPossibile specificare dei test con una annotazione @Target
73
AOTAOTLABLAB Fixture di test
import . . .public class RegexTest {private static Pattern pattern;@Beforepublic static void setUpBeforeClass() throws Exception {pattern = Pattern.compile("^\\d{5}([\\-]\\d{4})?$");
}@Testpublic void verifyZipCodeNoMatch() throws Exception {Matcher m = this.pattern.matcher("1357");boolean notValid = m.matches();assertFalse("Pattern did validate zip code", notValid);
}@Test(expected=IndexOutOfBoundsException.class)public void verifyZipCodeGroupException() throws Exception {Matcher m = this.pattern.matcher("12345-4321");boolean isValid = m.matches();m.group(2);
}}
74
AOTAOTLABLAB Fixture di classe
import . . .public class RegexTest {private static Pattern pattern;@BeforeClasspublic static void setUpBeforeClass() throws Exception {pattern = Pattern.compile("^\\d{5}([\\-]\\d{4})?$");
}@Testpublic void verifyZipCodeNoMatch() throws Exception {Matcher m = this.pattern.matcher("1357");boolean notValid = m.matches();assertFalse("Pattern did validate zip code", notValid);
}@Test(expected=IndexOutOfBoundsException.class)public void verifyZipCodeGroupException() throws Exception {Matcher m = this.pattern.matcher("22101-5051");boolean isValid = m.matches();m.group(2);
}}
75
AOTAOTLABLAB Fixture multiple
Si possono specificare più fixture per un test caseLe annotazioni di JUnit4 possono essere ripetute,
marcando con @Before o @BeforeClass diversimetodi
Ma non si può specificare l’ordine di esecuzioneVengono eseguite prima le fixture delle classi genitore
76
AOTAOTLABLAB Test suite
Meccanismo usato per raggruppare logicamente dei tested eseguirli assieme
L’annotazione @SuiteClasses raggruppa una lista diclassi, passate come parametro, in una test suite
L’annotazione @RunWith permette di impostare diversiesecutori di test
Di solito si usa Suite, già incluso nel framework
Esempio che mostra come gestire le suite nelle diverseversioni di JUnit
77
AOTAOTLABLAB Esempio di test suite (ver<4)
import junit.framework.Test;import junit.framework.TestSuite;
public class JUnit3Suite {public static Test suite() {TestSuite suite = new TestSuite();suite.addTest(RegexTest.class);suite.addTest(ParametricRegexTest.class);suite.addTest(TimedRegexTest.class);return suite;
}}
78
AOTAOTLABLAB Esempio di test suite
import org.junit.runner.RunWith;import org.junit.runners.Suite;import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)@SuiteClasses({
ParametricRegexTest.class,RegexTest.class,TimedRegexTest.class})
public class JUnit4Suite {}
79
AOTAOTLABLAB Esecuzione dei test
Si può eseguire una classe di test di JUnit 4 da un IDEcome EclipseRun As JUnit test
Oppure da linea di comandoEseguire la classe org.junit.runner.JUnitCore, passando
come argomento il nome completo di una classe di test
java org.junit.runner.JUnitCore <test class name>
81
AOTAOTLABLAB Esecuzione in Ant
<!-- Define any necessary Ant properties --><property name="src" value="./src" /><property name="lib" value="./lib" /><property name="classes" value="./classes" /><property name="test.class.name" value="com.xyz.MyTestSuite" /><!-- Set up the CLASSPATH to be used by JUnit --><path id="test.classpath"><pathelement location="${classes}" /><pathelement location="/path/to/junit.jar" /><fileset dir="${lib}"><include name="**/*.jar"/></fileset>
</path>
<!-- Define the Ant task for running JUnit --><target name="test"><junit fork="yes" haltonfailure="yes"><test name="${test.class.name}" /><formatter type="plain" usefile="false" /><classpath refid="test.classpath" />
</junit></target>
82
AOTAOTLABLAB Esecuzione di più test in Ant
. . .
<!-- Define the Ant task for running JUnit --><target name="test"><junit printsummary="yes" haltonfailure="yes">. . .<batchtest fork="yes"><fileset dir="${test.dir}">
<include name="**/*Test.java" /><include name="**/Test*.java" />
</fileset></batchtest>
</junit></target>
83
AOTAOTLABLAB Assert su array
Nuovo metodo di assert per confrontare il contenuto didue array
L’esempio seguente fallisce per le differenze tra glielementi
@Testpublic void verifyArrayContents() throws Exception {String[] actual = new String[] {
"JUnit 3.8.x", "JUnit 4", "TestNG"};String[] var = new String[] {
"JUnit 3.8.x", "JUnit 4.1", "TestNG 5.5"};assertEquals("the two arrays are not equal", actual, var);
}
84
AOTAOTLABLAB Test parametrici
In alcune applicazioni, può essere necessario scrivereun’enorme quantità di test
Nelle vecchie versioni di JUnit, la situazione eracomplicata
Per ripetere un test con diversi parametri occorrevascrivere un test case per ogni gruppo di parametri
JUnit permette le creazione di test generici che possonoessere eseguiti su parametri modificabili
Si può quindi creare un unico test case da eseguire piùvolte, una per ogni gruppo di parametri
85
AOTAOTLABLAB Test parametrici
Serie di passi per creare dei test parametrici
1. Creare un normale test, senza parametri2. Creare un metodo statico di fornitura dati: restituisce
una Collection, è annotato con @Parameter3. Aggiungere campi di classe per i parametri4. Scrivere un costruttore che riceve dei parametri e
inizializza i campi5. Specificare nella annotazione @RunWith che il test
case deve essere eseguito con la classeParameterized
86
AOTAOTLABLAB Esempio di test parametrico
Provare una espressione regolare su molti valoriSi noti che i valori di phrase e match non sono definiti
@Testpublic void verifyGoodZipCode() throws Exception {Matcher m = this.pattern.matcher(phrase);boolean isValid = m.matches();assertEquals("Pattern did not validate zip code", isValid, match);
}
87
AOTAOTLABLAB Fornitura dei parametri
Il passo successivo è creare un metodo di fornituraDeve essere static e deve restituire una CollectionDeve essere associato all’annotazione @ParametersEs. nel metodo si può creare un array multi-dimensionale diObject e convertirlo in una List
@Parameterspublic static Collection regExValues() {return Arrays.asList(new Object[][] {
{"22101", true },{"221x1", false },{"22101-5150", true },{"221015150", false }});
}
88
AOTAOTLABLAB Creare i campi e il costruttore
Ci sono due parametri, di tipo String e boolean, chedevono corrispondere a due campi nella classe
Poi bsogna creare un costruttore che colleghi i campi aivalori dei parametri
private String phrase;private boolean match;
public ParametricRegexTest(String phrase, boolean match) {this.phrase = phrase;this.match = match;
}
89
AOTAOTLABLAB Specificare la classe parametrizzata
Infine, bisogna specificare a livello di classe che il testdeve essere eseguito con la classe Parameterized,usando l’annotazione @RunWith
@RunWith(Parameterized.class)public class ParametricRegexTest {. . .
}