Verifica e Validazione del Software
Le attività di Verifica e Validazione (V & V) puntano a mostrare che il software è conforme alle sue specifiche (Verifica) e soddisfa le aspettative del cliente (Validazione).
- Verifica: Are we making the right product?
- Validazione: Are we making the product right?
Gli approcci per le attività di Verifica e Validazione
- Analisi dinamica: processo di valutazione di un sistema software o di un suo componente basato sulla osservazione del suo comportamento in esecuzione. Di solito solo queste tecniche si identificano come testing.
- Analisi statica: processo di valutazione di un sistema o di un suo componente basato sulla sua forma, struttura, contenuto, documentazione senza che esso sia eseguito. Esempi sono: revisioni, ispezioni, recensioni, analisi data flow.
- Analisi formale: uso di rigorose tecniche matematiche per l’analisi di algoritmi. E’ usata soprattutto per la verifica del codice e dei requisiti, specie quando questi sono specificati con linguaggi formali (es. Z, VDM).
Definizioni IEEE per il Testing
Standard IEEE 610.12-1990:
(1) The process of operating a system or component under specified conditions, observing or recording the results, and making an evaluation of some aspect of the system or component.
IEEE Std.729-1983
(2) The process of analyzing a software item to detect the differences between existing and required conditions (that is, bugs) and to evaluate the features of the software item.
See also: acceptance testing; benchmark; checkout; component testing; development testing; dynamic analysis; formal testing; functional testing; informal testing; integration testing; interface testing; loopback testing; mutation testing; operational testing; performance testing; qualification testing; regression testing; stress testing; structural testing; system testing; unit testing.
Alcune definizioni
- Un programma è esercitato da un caso di test (sottoinsieme dei dati di input)
- Un test è formato da un insieme di casi di test
- L’esecuzione del test consiste nell’esecuzione del programma per tutti i casi di test
Scopi del Testing
Il testing può avere diversi obiettivi:
- Dimostrare al cliente e allo sviluppatore che il software soddisfa i suoi requisiti
- Si parla di Test di Convalida
- Verifica che il software si comporti adeguatamente usando un insieme di casi di test che riflette l’uso previsto
- Tale test ha successo se tutto funziona come ci si aspetta
- Scoprire gli errori o difetti del software
- Si parla di Test dei Difetti
Definizioni
- Errore (umano): incomprensione umana nel tentativo di comprendere o risolvere un problema, o nell’uso di strumenti.
- Difetto (fault o bug): manifestazione nel software di un errore umano, e causa del fallimento del sistema nell’eseguire la funzione richiesta.
- Malfunzionamento (failure): incapacità del software di comportarsi secondo le aspettative o le specifiche; un malfunzionamento ha una natura dinamica: accade in un certo istante di tempo e può essere osservato solo mediante esecuzione.
Un esempio
Function RADDOPPIA ( )
....
read (x);
y := x*x;
write (y)
...
ERRORE di editing/digitazione
DIFETTO => “*” invece di “+”
DIFETTO causato da un errore
MALFUNZIONAMENTO => il valore visualizzato è errato
Possibile MALFUNZIONAMENTO in esecuzione… (può verificarsi o meno: dipende dall’input)
Relazione fra errore, difetto e malfunzionamento
Test dei Difetti
Ha lo scopo di scoprire i difetti di un programma.
Approccio usato: scoprire la presenza di difetti osservando i malfunzionamenti!
Un test dei difetti ha successo se porta il programma a comportarsi in maniera scorretta (cioè esibisce malfunzionamenti).
Il testing può sono dimostrare la presenza dei difetti, ma non la loro assenza!! (Tesi di Dijkstra)
Problemi e Limitazioni
La correttezza di un programma è un problema indecidibile!
Problemi:
- non vi è garanzia che se alla n-esima prova un modulo od un sistema abbia risposto correttamente (ovvero non sono stati più riscontrati difetti), altrettanto possa fare alla (n+1)-esima;
- Impossibilità di produrre tutte le possibili configurazioni di valori di input (test case) in corrispondenza di tutti i possibili stati interni di un sistema software.
Ulteriori Problemi
In molti campi dell’ingegneria, il testing è semplificato dall’esistenza di proprietà di continuità.
Se un ponte resiste ad un carico di 1000 tonnellate, allora resisterà anche a carichi più leggeri.
Nel campo del software si ha a che fare con sistemi discreti, per i quali piccole variazioni nei valori d’ingresso possono portare a risultati scorretti.
Il testing esaustivo (ideale) è condizione necessaria per poter valutare la correttezza di un programma a partire dal testing.
L’impossibilità del Testing Esaustivo!
Se il ciclo fosse eseguito al più 20 volte, ci possono essere oltre 100.000 miliardi di possibili esecuzioni diverse!!!
Se ogni test fosse elaborato in 1 ms, sarebbero necessari 3170 anni!!!
Il processo di Software Testing
Un processo di testing non può dimostrare la correttezza, ma può consentire di acquistare fiducia nel software, mostrando che esso è pronto per l’uso operativo!
Un processo di testing deve basarsi su approcci ingegneristici atti a ridurre lo sforzo (inteso come impiego di risorse umane, tecnologiche e di tempo) necessario per individuare il massimo numero possibile di difetti prima che il prodotto sia rilasciato!
La qualità di un Processo di Testing
Il Testing deve essere:
Efficace
- Condotto attraverso strategie che consentano la scoperta di quanti più difetti possibili
Efficiente
- In grado di trovare difetti provando il minor numero possibile di casi di test
- Circa il 40% dei costi di produzione del software per il raggiungimento di ragionevoli livelli di qualità sono richiesti dal testing
Ripetibile
- Potrebbe non essere possibile se l’esecuzione del caso di test influenza l’ambiente di esecuzione senza la possibilità di ripristinarlo
- Potrebbe non essere possibile se nel software ci sono degli elementi indeterministici
- Ovvero dipendenti da input non controllabili
Il Processo di Software Testing
Diversi Livelli di Testing
Livello Produttore:
- Testing di Unità (o di Componente)
- Testing di Integrazione
- Testing di Sistema
Livello Cooperativo Produttore-Utente Privilegiato:
- Alpha testing
- Beta testing
Livello Utente:
Fasi del Testing (a livello Produttore)
Livello Produttore
Test dei Componenti (o di Unità)
- Testing di singole unità di codice (funzioni, oggetti, componenti riusabili);
- É responsabilità di chi sviluppa il componente;
- I test sono derivati in base all’esperienza dello sviluppatore.
Test di Sistema
- Testing di gruppi di componenti integrati per formare il sistema o un sotto-sistema;
- É responsabilità di un team indipendente per il testing;
- I test sono definiti in base alla specifica del sistema.
Livello Produttore (segue)
Test di Integrazione
- Richiede la costruzione del sistema a partire dai suoi componenti ed il testing del sistema risultante per scoprire problemi che nascono dall’interazione fra I vari componenti.
- Richiede l’identificazione di gruppi di componenti che realizzano le varie funzionalità del sistema e la loro integrazione mediante componenti che li fanno lavorare insieme.
- Partendo da una architettura organizzata gerarchicamente, le integrazioni possono essere realizzate con approccio top-down o bottom-up o misto.
Strategie per il Testing di Integrazione
Esecuzione del testing di integrazione
- Costruzione di Moduli guida (driver): invocano l’unità sotto test, inviandole opportuni valori, relativi al test case.
- Moduli fittizi (stub):
- sono invocati dall’unità sotto test;
- emulano il funzionamento della funzione chiamata rispetto al caso di test richiesto (tenendo conto delle specifiche della funzione chiamata);
- quando la funzione chiamata viene realizzata e testata, si sostituisce lo stub con la funzione stessa.
Livello produttore-utente privilegiato
Alpha testing:
- uso del sistema da parte di utenti reali ma nell’ambiente di produzione e prima della immissione sul mercato.
Beta Testing:
- installazione ed uso del sistema in ambiente reale prima della immissione sul mercato.
Tipicamente adottati dai produttori di packages per mercato di massa!
Testing di Accettazione
Testing effettuato sull’intero sistema sulla base di un piano e di procedure approvate dal cliente (o utente); l’obiettivo é quello di mettere il cliente, l’utente o altri a ciò preposti (collaudatori o enti ad hoc) in condizione di decidere se accettare il prodotto.
Occorre provare che il software fornisce tutte le funzionalità, le prestazioni, l’affidabilità, etc. richieste, e che non fallisca.
É in genere un testing black-box (a scatola nera):
- Basato solo sulle specifiche del software;
- I Tester non accedono al suo codice.
è a carico del committente; è più una dimostrazione che un test!
Problemi di base di un processo di testing
- Selezione dei Casi di Test
- Valutazione dei risultati del Test
- Terminazione del Testing
1. Valutazione dei risultati del test
Condizione necessaria per effettuare un test: conoscere il comportamento atteso per poterlo confrontare con quello osservato.
L’Oracolo conosce il comportamento atteso per ogni caso di prova. Due tipi di Oracolo:
- Oracolo umano: si basa sulle specifiche o sul giudizio.
- Oracolo automatico:
- generato dalle specifiche (formali);
- stesso software ma sviluppato da altri;
- versione precedente (test di regressione).
2. Terminazione del testing
Dal momento che il testing esaustivo è, in generale, irraggiungibile, altri criteri sono proposti per valutare quando il testing possa essere terminato:
- Criterio temporale: periodo di tempo predefinito;
- Criterio di costo: sforzo allocato predefinito;
- Criterio di copertura: percentuale predefinita degli elementi di un modello di programma; legato ad un criterio di selezione dei casi di test;
- Criterio statistico: MTBF (mean time between failures) predefinito e confronto con un modello di affidabilità esistente.
3. Problema della selezione dei casi di test
Premesso che:
- Un programma è esercitato da un caso di test (sottoinsieme dei dati di input)
- Un test è formato da un insieme di casi di test
- L’esecuzione del test consiste nell’esecuzione del programma per tutti i casi di test
- Un test ha successo se rileva uno o più malfunzionamenti del programma
Test Ideale ed Esaustivo
Un test è ideale se l’insuccesso del test implica la correttezza del programma
Un test esaustivo è un test che contiene tutti i dati di ingresso al programma:
- un test esaustivo è un test ideale;
- un test esaustivo non è pratico e quasi sempre non è fattibile.
Obiettivo realistico: selezionare casi di test che approssimano un test ideale.
Criterio di Selezione dei Test
Specifica le condizioni che devono essere soddisfatte da un test e consente di selezionare più test per uno stesso programma.
- Un criterio di selezione di test C è affidabile per un programma se per ogni coppia di test selezionati da C, T1 e T2, se il test T1 ha successo, allora anche T2 ha successo e viceversa. Quindi tutti i possibili esemplari di test generati dal criterio C hanno la stessa capacità di ricerca di un malfunzionamento.
- Un criterio di selezione di test C è valido per un programma se, qualora il programma non è corretto, esiste almeno un test selezionato da C che ha successo.
- Se un criterio è affidabile e valido, allora qualsiasi test T generato da C per un programma non corretto avrà successo.
Esempio*
Pro
gram raddoppia
(input, output);
var x, y: integer;
begin
read(x);
y:= x*x;
write(y);
e
nd
- Criterio affidabile ma non valido: T deve contenere sottoinsiemi di {0, 2}
- Criterio valido ma non affidabile: T deve contenere sottoinsiemi di {0,1, 2, 3, 4}
- Criterio valido e affidabile: T deve contenere almeno un valore maggiore di 3
Selezione dei casi di test
Teorema di Goodenough e Gerhart
Il fallimento di un test T per un programma P, selezionato da un criterio C affidabile e valido, permette di dedurre la correttezza del programma P.
Teorema di Howden
Non esiste un algoritmo che, dato un programma arbitrario P, generi un test ideale finito, e cioè un test definito da un criterio affidabile e valido.
Al di là di casi banali, in generale non è possibile costruire un criterio di selezione generale di test valido e affidabile che non sia il test esaustivo.
Obiettivi pratici:
- massimizzare il numero di malfunzionamenti scoperti (richiede molti casi di test);
- minimizzare il numero di casi di test (e quindi il costo del testing).
È preferibile usare più di un criterio di selezione dei test!
Due principali Famiglie di Tecniche di Testing
Testing funzionale (o Black Box)
- Richiede l’analisi degli output generati dal sistema (o da suoi componenti) in risposta ad input (test cases) definiti sulla base della sola conoscenza dei requisiti del sistema (o di suoi componenti).
- Esempi: Testing basato sui requisiti; Testing delle partizioni (o delle classi di equivalenza); Testing basato su Tabelle di Decisione; Testing basato su Grafi Causa-Effetto…
Testing strutturale (o White Box)
- Fondato sulla conoscenza della struttura del software ed in particolare del codice, degli input associati e dell’oracolo, per la definizione dei casi di prova.
- Es.: Statement Testing, Branch Testing, Path Testing, …