![]() ![]() |
|
![]() ![]() |
Il termine bug (insetto) è usato
comunemente per indicare gli errori nei programmi.
Leggenda vuole che sia stato adottato nel gergo informatico all'epoca dei computer elettromeccanici in occasione del ritrovamento di un insetto (una falena) intrappolata dentro un interruttore a relè (1947, nel Mark II della Harvard University).
![]() In realtà l'uso del termine per indicare un insetto immaginario nascosto in un apparecchio e responsabile di tutti i malfunzionamenti era probabilmente già in auge dal secolo precedente. I bachi di cui ci occuperemo non sono davvero insetti ma neppure immaginari.
|
![]() ![]() |
|
![]() ![]() |
Come molte altre attività umane (e non), la scrittura di
programmi non è esente da errori di varia natura che ne
possono compromettere il corretto funzionamento.
Con la sempre maggiore diffusione che le applicazioni software hanno nelle nostre attività quotidiane (es. cellulari, bancomat, mezzi di trasporto, apparecchiature mediche) il verificarsi di errori potrebbe influenzare pesantemente le nostre esistenze.
|
![]() ![]() |
|
![]() ![]() |
La domanda che sorge spontanea anche ad un profano dell'informatica
è quindi:
Purtroppo la risposta è che nessuno può darci tale garanzia assoluta... però è nostro dovere cercare di acquisire la maggiore fiducia possibile nel fatto che il programma che abbiamo scritto sia corretto, al punto da essere disposti ad affidare al programma persino la nostra incolumità e quella degli altri.
Tralasciando l'impiego di metodi formali (che non può essere oggetto di questo corso), le migliori armi a nostra disposizione per eliminare quanti più errori possibili sono:
Nota: difetti e malfunzionamenti non sono sempre in corrispondenza biunivoca: (1) l'esecuzione di un programma difettoso può produrre comunque risultati corretti, (2) esistono malfunzionamenti causati da combinazioni di più difetti e dipendenti dal particolare contesto di esecuzione. |
![]() ![]() |
|
![]() ![]() |
Qualsiasi applicazione composta da più classi e metodi
può essere controllata più facilmente utilizzando (anche
in fase di sviluppo) il collaudo delle singole unità
separatamente (al livello di granularità del singolo metodo o
di gruppi ristretti di metodi cooperanti).
Il collaudo procede compilando ciascuna classe assieme a un semplice programma detto infrastruttura di collaudo che invoca i metodi da collaudare con opportuni valori e ne osserva l'esito. È buona pratica eseguire il collaudo in maniera preventiva, prima di aver terminato la realizzazione dell'intera applicazione, per poter intervenire tempestivamente anche sulla riprogettazione del sistema in seguito alla scoperta di errori difficili da gestire adeguatamente.
|
![]() ![]() |
|
![]() ![]() |
Gli argomenti per il collaudo possono provenire da fonti diverse:
L'uso di valori memorizzati in un file è preferibile perché copre gli altri casi (es. il contenuto del file può essere generato in maniera pseudocasuale) e rende più facile e veloce ripetere l'esperimento dopo aver modificato e ricompilato il codice.
I valori utilizzati per il collaudo dovrebbero coprire le seguenti categorie:
|
![]() ![]() |
|
![]() ![]() |
Nei casi di prova, oltre ai dati in ingresso è indispensabile
conoscere anche i dati attesi in uscita (assumendo che il programma
funzioni correttamente).
Infatti, quando eseguiamo il collaudo sui casi di prova dobbiamo confrontare i valori prodotti in output con i risultati attesi.
Per poter verificare i dati in output è quindi conveniente aver memorizzato in un file i valori attesi per ogni caso di prova. Tali valori possono essere generati:
È importante conservare i casi di prova e i rispettivi output:
|
![]() ![]() |
|
![]() ![]() |
Quando si collaudano le funzionalità del programma senza
conoscere o considerare la sua struttura interna (es. software
proprietario o troppo complesso) si parla di collaudo a scatola
chiusa (black-box testing o test funzionale).
Questo è il tipo di test più diffuso perché si
adatta facilmente a tutti i livelli di sviluppo delle applicazioni ed
è meno costoso (più facile da sviluppare) di altri tipi
di test.
Per accertare il corretto funzionamento del programma su tutti i possibili valori in ingresso (positivi, limite e negativi) avremmo però bisogno di infiniti casi di prova a scatola chiusa, mentre dobbiamo accontentarci di un numero finito. Quando si conosca la struttura del programma è invece opportuno utilizzare tecniche di collaudo trasparente (white-box testing o test strutturale), scegliendo i casi di prova in modo che ciascuna porzione del programma venga collaudata almeno una volta. Infatti, se un frammento di codice è difettoso ma nessun test lo esegue il difetto non viene rilevato. Poter offrire una migliore copertura del collaudo permette di aumentare la fiducia nella correttezza dell'intero programma. Infine è importante focalizzare i test su difetti comunemente presenti in molti programmi, utilizzando il cosiddetto collaudo basato su difetti (fault-based testing). Ad esempio, se vengono usati array è opportuno controllare che non si verifichino tentativi di accesso a posizioni inesistenti (out-of-bounds).
|