Sei sulla pagina 1di 18

Testing:

Schema:
- Quali sono gli obiettivi della verifica?
- Quali sono i principali approcci alla verifica?
o Che tipo di garanzia otteniamo attraverso i test?
o Come si possono fare sistematicamente i test?
o Come possiamo rimuovere i difetti (debug)?
• Quali sono i principali approcci all'analisi del software?
Informali vs. formali.

Bisogno della verifica:


I progettisti sono fallibili anche se sono abili e seguono solidi principi.
Tutto deve essere verificato, ogni qualità, processo e prodotti richiesti, anche la stessa verifica.

Proprietà della verifica:


Potrebbe non essere binario (OK, non OK).
- La gravità del difetto è importante, alcuni difetti possono essere tollerati.
• Può essere soggettivo o oggettivo:
• Esempio: usabilità
• Anche le qualità implicite devono essere verificate:
• Perché i requisiti sono spesso incompleti.
• Esempio: robustezza.

Approccio alla verifica:


Sperimenta il comportamento del prodotto:
- Campiona comportamenti tramite test.
- Obbiettivo è trovare "controesempi".
- Tecnica dinamiche.
• Analizzare il prodotto per dedurne l'adeguatezza:
- Studio analitico delle proprietà.
- tecnica statica.

Test e mancanza di “continuità”:


• Testare i comportamenti dei campioni esaminando "casi di test".
• Impossibile estrapolare il comportamento del software da una serie finita di casi di test.
• Nessuna continuità di comportamento può esibire il comportamento corretto in infiniti casi, ma può
comunque essere errato in alcuni casi.

Verifica in Ingegneria:
Esempio del Design Bridge. Un test può assicurare infinite situazioni corrette.
Commento: Se ommettiamo questo, la routine funziona se l’altro non viene mai toccato. (cioè se la
dimensione della tabella è una potenza del 2).

Obbiettivi del test:


• Mostrare la presenza di bug.
• Se i test rivelano errori, non possiamo concludere che il software sia privo di difetti.
• Tuttavia, dobbiamo fare dei test guidati da principi solidi e sistematici.
• Dovrebbe aiutare a isolare gli errori, per facilitare il debugging.
• Dovrebbe essere ripetibile:
- Ripetere lo stesso esperimento, dovremmo ottenere gli stessi risultati: ma ciò potrebbe
non essere vero a causa dell’effetto dell’ambiente di esecuzione sui test, o a causa del non
deterministico.
• Dovrebbero essere precisi.

Basi teoriche dei test:

Definizione 1:
P => Programma; D => Dominio di input; R => Dominio di output
Quindi: P: D -> R (Potrebbe essere parziale)

Correttezza definita da: OR ⊆ D X R


- P(d) corretto se: <d, P(d)> ∈ OR
- P corretto se: tutti i P(d) sono corretti.
-
Definizione 2:
• Fallimento:
- P(d) non è corretto:
▪ Potrebbe non essere definito (stato di errore) o potrebbe non essere il risultato
sbagliato.
• Errore (Difetto):
- qualsiasi cosa che possa causare un fallimento:
▪ Errori di battitura. Il programma ha dimenticato di verificare: x=0.
• Colpa:
- stato intermedio errato inserito dal programma.

Definizione 3:
• Test caso t:
- Un elemento di D.
• Test set T:
- un sottoinsieme finito di D.
• Il test ha esito positivo se P(t) è corretto.
• Test eseguito con successo se P è corretto per tutte le t in T.

Definizione 4:
• Test set ideale T:
- Se P è errato, esiste un elemento di T tale che P(d) è errato.
• Se esistesse un test set ideale per qualsiasi programma, potremmo provare la correttezza del
programma testandolo.

Criterio di test:
• Un criterio C definisce un sottoinsieme finiti di D (test set):
- C ⊆ 2^D
• Un test set T soddisfa C se è un elemento di C:
• Esempio:

Proprietà dei criteri 1:


• C è consistente:
- per ogni coppia T1, T2 che soddisfa C, T1 ha esito positivo se e solo se T2 ha esito positivo.
Quindi uno di loro fornisce le "stesse" informazioni.
• C è completo:
- se P non è corretto, esiste un test set T di C che non ha esito positivo.
• C è completo e consistente:
- Identifica un test set ideale.
- Consente di dimostrare la correttezza.

Proprietà dei criteri 2:


• C1 è più fine di C2:
- Per qualsiasi programma P
- Per ogni T1 che soddisfa C1 esiste un sottoinsieme T2 di T1 che soddisfa C2.

Proprietà delle definizioni:


• Nessuno è efficace, ovvero non esiste alcun algoritmo che indichi se un programma, un test set o
un criterio hanno tale proprietà.
• In particolare, non esiste un algoritmo per derivare un test set che dimostrerebbe la correttezza del
programma. Non esiste un criterio costruttivo coerente e completo.
Principi di test empirici:
• Tentativo di compromesso tra l'impossibile e l'inadeguato.
• Trova la strategia per selezionare casi di test significativi:
- significativo = ha un alto potenziale di scoprire la presenza di errori.

Principio di copertura completa:


• Cerca di raggruppare elementi di D in sottodomini D1, D2, ..., 𝐷𝑛 in cui è probabile che qualsiasi
elemento di ciascun 𝐷𝑖 abbia un comportamento simile:
o D = D1 ∪ D2 ∪ ... ∪ Dn.
• Seleziona un test come rappresentante del sottodominio.
• Se Dj ∩ Dk ≠ 0 , per tutti j, k (partizione), qualsiasi elemento può essere scelto da ciascun
sottodominio.
• Altrimenti, scegliere i rappresentanti per ridurre al minimo il numero di test, pur rispettando il
principio.
• Esempio di partizionamento:

Test in piccolo:
Testiamo singoli moduli:
• Test BLACK BOX (funzionali) - criteri di partizionamento basati sulle specifiche del modulo. Test di
ciò che il programma dovrebbe fare.
• Test WHITE BOX (strutturali) - criteri di partizionamento basati sul codice interno del modulo. Test
di cosa fa il programma.

Test White Box:


Deriva test case dal codice del programma.

Test di copertura strutturale:


• Criteri di inadeguatezza: se parti significative della struttura del programma non vengono testate, i
test non sono adeguati.
• Controllare i criteri di copertura del flusso:
- Copertura dello stato
- Copertura dei bordi
- Copertura delle condizioni
- Copertura del percorso

Criteri di Copertura dello stato:


Selezionare un test set T in modo tale che ogni istruzione elementare in P sia eseguita almeno una volta da
qualche d in T.
• Un dato di input esegue molte istruzioni -> tenta di ridurre al minimo il numero di casi di test
mantenendo comunque la copertura desiderata.
Esempio:

Debolezza del criterio:


{<x=-3} Copre tutte le dichiarazioni.
Non esegue il caso quando x è positivo e il ramo non è inserito.

Criterio di Copertura dei bordi:


Selezionare un test set T in modo tale che ogni bordo (ramo) del flusso di controllo sia eseguito almeno una
volta da qualche d in T. Ciò richiede la formalizzazione del concetto del grafico di controllo e come
costruirlo.
- I bordi rappresentano le istruzioni.
- I nodi alle estremità di un bordo rappresentano l'entrata e l'uscita dell’istruzione.

Regole di costruzione del grafico di controllo:


Semplificazione:
Una sequenza di bordi può essere compressa in un solo bordo.

Criterio della copertura di condizione:


Selezionare un test set T in modo tale che ogni lato del bordo di controllo di P venga attraversato e che tutti
i possibili valori dei componenti delle condizioni composte vengano esercitati almeno una volta.
- È più fine della copertura dei bordi.

Debolezza (Weakness):
{<x = 0, z = 1>, <x = 1, z = 3>} provoca l'esecuzione di tutti i bordi, ma non espone a zero
il rischio di una divisione.

Criterio di copertura del percorso:


Seleziona un test set di T che attraversa tutti i percorsi dal nodo iniziale a quello finale del flusso di controllo
di P. È più fine dei precedenti tipi di copertura, tuttavia, il numero di percorsi potrebbe essere troppo
grande o addirittura infinito (vedere loop while).
- Devono essere previsti ulteriori vincoli.

Il problema di fattibilità:
I comportamenti sintatticamente indicati (istruzioni, bordi, ecc.) Sono spesso impossibili:
- codice irraggiungibile, bordi non realizzabili, percorsi, ecc.
• I criteri di adeguatezza possono essere impossibili da soddisfare:
- Giustificazione manuale per omettere ogni test case impossibile.
- "Punteggi" adeguati basati sulla copertura:
o esempio: copertura dell'istruzione del 95%.

Ulteriore problema:
Cosa succede se il codice omette l'implementazione di alcune parti delle specifiche?
I casi di white box test derivati dal codice ignoreranno quella parte delle specifiche!

Test Black box:


Deriva test case dalle specifiche.
La specifica:
Il programma riceve come input un record che descrive una fattura. (Viene fornita una descrizione
dettagliata del formato del record.) La fattura deve essere inserita in un file di fatture ordinato per data. La
fattura deve essere inserita nella posizione appropriata: se nel file sono presenti altre fatture con la stessa
data, la fattura deve essere inserita dopo l'ultima. Inoltre, è necessario eseguire alcuni controlli di coerenza:
il programma dovrebbe verificare se il cliente è già in un file di clienti, se i dati del cliente nei due file
corrispondono, ecc.

Hai considerato questi casi?


• Una fattura la cui data è la data corrente.
• Una fattura la cui data è precedente alla data corrente (questo potrebbe essere addirittura vietato
dalla legge). Questo caso, a sua volta, può essere suddiviso nelle due seguenti sottosezioni:
o Una fattura la cui data è la stessa di quella esistente.
o Una fattura la cui data non esiste in nessuna fattura precedentemente registrata.
• Diverse fatture errate, che controllano diversi tipi di incoerenze.

Tecniche sistematiche di Black box:


• Test guidato da specifiche logiche (pre e post condizioni).
• Test guidato dalla sintassi.
• Test basati sulla tabella decisionale.
• Test basato sul grafico causa-effetto.

Specifica la logica di inserimento del record della fattura in un file:


Test guidato dalla sintassi:
Valuta di provare un interprete della seguente lingua:

• Applicare il principio di copertura completa a tutte le regole grammaticali.


• Genera un test case per ciascuna regola della nota grammaticale, tuttavia il test case potrebbe coprire
anche altre regole.
• Nota: le specifiche sono formali e la generazione del test può essere automatizzata.

Test basati su una tabella decisionale:


“L'editor di testo può presentare parti di testo in tre diversi
formati: testo semplice (p), grassetto (b), corsivo (i). I
seguenti comandi possono essere applicati a ciascuna
porzione di testo: rendere il testo semplice (P), rendere
grassetto (B), rendere corsivo (I), enfatizzare (E), enfatizzare
super (SE). Sono disponibili comandi per impostare
dinamicamente: E in modo che significhi B o I (indichiamo
rispettivamente comandi come E = B ed E = I). Allo stesso
modo, SE può essere impostato dinamicamente per indicare
B (comando SE = B) o I (comando SE = I), oppure B e I
(comando SE = B + I.)”

Grafici effetto causa:


Il grafico AND / OR rappresenta la corrispondenza tra cause ed effetti.

Ulteriori vincoli:
"Sia B che I escludono P (cioè: non si può chiedere sia il
testo normale che il testo in corsivo per la stessa porzione
di testo.) E e SE si escludono a vicenda."
Criterio di Copertura:
• Generare tutte le possibili combinazioni di input e verifica l’output.
• Può ridurre il numero andando indietro negli output
- Nodo OR con output vero:
▪ utilizzare combinazioni di input, con un solo input vero.
- Nodo AND con output falso:
▪ utilizzare combinazioni di input con un solo input falso.

Test delle condizioni al contorno:


I criteri di test suddividono il dominio di input nelle classi, assumendo che il comportamento sia "simile" per
tutti i dati all'interno di una classe.
Tuttavia, alcuni tipici errori di programmazione si trovano al confine tra classi diverse.

Criterio:
Dopo aver partizionato il dominio di input D in diverse classi, bisogna testare il programma utilizzando i
valori di input non solo "all'interno" delle classi, ma anche ai loro limiti. Questo vale per entrambe le
tecniche di: white box e black box.

Il problema dell’oracolo:
Come ispezionare i risultati delle esecuzioni dei test per rilevare guasti:
• Gli oracoli sono richiesti in ogni fase del test.
• Gli oracoli di test automatizzati sono necessari per l'esecuzione di grandi quantità di test.
• Gli oracoli sono difficili da progettare, nessuna ricetta universale.

Testing in generale:
• Test del modulo
- Test di un singolo modulo
• Test d'integrazione
- Integrazione di moduli e sottosistemi
• Test di sistema
- Testare l'intero sistema
• Test di accettazione
- Eseguito dal cliente

Test del modulo:


Impalcature necessarie per creare l'ambiente in cui il modulo dovrebbe essere testato.
• Stubs: moduli utilizzati dal modulo in prova.
• Driver: modulo che attiva il modulo in prova.
Test di un modulo funzionale:

Test d'integrazione:
• Approccio big bang
Prima prova singoli moduli in isolamento.
- Quindi testare il sistema integrato.
• Approccio incrementale
- I moduli vengono progressivamente integrati e testati
Può procedere sia dall'alto verso il basso che dal basso verso l'alto secondo la relazione USES.

Test di integrazione e relazione USES:

Se il processo di integrazione e test dal basso verso l'alto richiede solo driver.
Altrimenti, se procediamo dall'alto in basso sono necessari solo stubs.

Testing nella programmazione orientata agli oggetti (POO):


Nuovi problemi quali: ereditarietà, generalizzazione, polimorfismo e dynamic binding.
Esistono ancora problemi non risolti (aperti).

Ereditarietà:
Data una gerarchia di classi, come testare le classi della gerarchia?
• "Appiattire" l'intera gerarchia e considerare ogni classe come un componente totalmente
indipendente, quindi non sfrutta l’incrementalità.
• Trovare un modo ad hoc per sfruttare la gerarchia.
Una strategia d’esempio:
• Un test che non deve essere ripetuto per nessun erede.
• Un test che deve essere eseguito per l'erede di classe X e tutti i suoi ulteriori eredi.
• Un test che deve essere ripetuto applicando gli stessi dati di input, ma verificando che l'output non
sia (o sia) modificato.
• Un test che deve essere modificato aggiungendo altri parametri di input e verificando che l'output
cambi di conseguenza.

Preoccupazioni separate nei test:


• Il test per la funzionalità non è sufficiente.
• Test di sovraccarico.
• Test di robustezza.
• Test di regressione:
o Organizzare i test allo scopo di verificare eventuali regressioni del software durante la sua
vita. - Vale a dire, degradazioni della correttezza o altre qualità dovute a successive
modifiche.

Test di sistemi simultanei (concurrent) e in real-time:


• Il non determinismo inerente alla concorrenza (concurrent) influisce sulla ripetibilità.
• Per i sistemi in real-time, un caso di test è costituito non solo dai dati di input, ma anche dai tempi
in cui tali dati vengono forniti.

Analisi:
Analisi vs. Testing:
• Il test caratterizza una singola esecuzione.
• L'analisi caratterizza una classe di esecuzioni; si basa su un modello.
• Hanno vantaggi e svantaggi complementari.

Tecniche di analisi informale Procedure dettagliate del codice:


• Indicazioni raccomandate:
– Piccolo numero di persone (da tre a cinque).
– I partecipanti ricevono documentazione scritta dal progettista pochi giorni prima della riunione.
– Durata predefinita della riunione (alcune ore).
– Focus sulla scoperta di errori, non sulla loro correzione.
– Partecipanti: designer, moderatore e segretario.
– Migliorare la cooperazione; nessuna valutazione delle persone:
o L'esperienza dimostra che la maggior parte degli errori viene rilevata dal progettista
durante la presentazione, mentre cerca di spiegare il design ad altre persone.

Tecniche di analisi informale Ispezione del codice:


• Una tecnica di lettura che mira alla scoperta di errori.
• Basato su liste di controllo; per esempio:
o Uso di variabili non inizializzate;
o salto in loop;
o loop interminabili;
o Indici array fuori limite;
o ecc.
Prove di correttezza:
Un programma e le sue specifiche (notazione Hoare):
Prova mediante sostituzione all'indietro:

Regole della prova:


Notazione: If Richiesta1 && Richiesta2 sono state dimostrate, si può dedurre la Richiesta3, t.c.:
𝑅𝑖𝑐ℎ𝑒𝑠𝑡𝑎1, 𝑅𝑖𝑐ℎ𝑖𝑒𝑠𝑡𝑎2
𝑅𝑖𝑐ℎ𝑖𝑒𝑠𝑡𝑎3
Regole della prova nei linguaggi:

Prova di correttezza:
• Correttezza parziale:
- La validità di {Pre} Program {Post} garantisce che se il Pre è valido prima dell'esecuzione del
Program e se il programma terminerà, Post-condizione sarà raggiunto.
• Correttezza totale:
– Pre garantisce la chiusura dei programmi e la verità su Post.
Questi problemi non si possono descrivere.

Invenzione del loop invariante:


• Passo difficile e creativo.
• Non può essere costruito automaticamente.

Programmi con array:


{Pre} a(i) := expression; {Post}
Pre denota l'affermazione ottenuta da Post sostituendo ogni occorrenza di una variabile indicizzata a (j) con
il termine.
If (j = i) then {
expression;
}
else {a(j);}
Prova di correttezza:
Può essere fatto utilizzando il seguente invariante di loop:

Prove di correttezza in generale:


Possiamo dimostrare la correttezza delle operazioni (ad es. Operazioni su un tipo di dati astratto). Quindi
utilizzare il risultato della dimostrazione per provare i frammenti che operano su oggetti dell'ADT.

Avendo dimostrato ciò:

Possiamo quindi dimostrare le proprietà dei


programmi usando le tabelle, ad esempio,
che dopo aver eseguito la sequenza:
Insert(T, x);
Delete(T, x);
x non è presente in T.
Una valutazione delle prove di correttezza:
Ancora non utilizzato nella pratica, però:
- Può essere usato per porzioni molto critiche.
- Le asserzioni possono essere la base per un modo sistematico di inserire controlli in Runtime.
- Le prove possono diventare più pratiche man mano che vengono sviluppati strumenti di
supporto più potenti.
- La conoscenza della teoria della correttezza aiuta i programmatori ad essere rigorosi.
Esecuzione simbolica:
• Può essere visto come una via di mezzo tra test e analisi.
• Esegue il programma su valori simbolici.
• Un'esecuzione simbolica corrisponde a molte esecuzioni effettive.

Esempio (2):
Quando il controllo raggiunge la condizione, i valori simbolici non consentono all'esecuzione di selezionare
un ramo. Si può scegliere un ramo e registrare la scelta in una condizione di percorso.
Risultato:
<{a = A, y = Y + 5, x = 2 * Y + A + 7},
Esecuzione del percorso: <1, 3, 4>, Condizione del percorso: Y + 2 ≤ A>

Regole di esecuzione simbolica (1):


Stato simbolico:
< valore_variabile_simbolica, esecuzione_percorso, condizione_di_percorso >

• Read(x) => rimuove qualsiasi associazione esistente per x e aggiunge l'associazione x = X, dove X è
un valore simbolico appena introdotto.
• Write(expression) => output (n) = valore_simbolico_calcolato (contatore n inizializzato su 1 e
incrementato automaticamente dopo ogni istruzione di output).
• x := expression => costruire il valore simbolico di espressione, SV; sostituisce l'associazione
precedente per x con x = SV.
• Dopo l'esecuzione dell'ultima istruzione di una sequenza che corrisponde a un bordo del grafico di
controllo, aggiungere il bordo al percorso di esecuzione.
• If cond then S1; else S2; end if
• While cond loop … end loop => la condizione viene valutata simbolicamente
▪ Eval (cond)
o If eval (cond) => vero o falso quindi l'esecuzione procede seguendo il ramo appropriato.
o in caso contrario, fare una scelta non deterministica di vero o falso e congiungere
eval(cond) (oppure, not eval (cond)) alla condizione del percorso.

Programmi con array:


Sia A1 il valore simbolico dell'array quando viene eseguita l'istruzione a(i) = exp.
Quindi, dopo l'esecuzione dell'istruzione, a riceve il nuovo valore simbolico A2, indicato come:
A2 = A1 <i, exp>, una scorciatoia per: tutti i k se:
if (k = i) then A2 (k) = exp; else A2(k) = A1(k);
Esecuzione simbolica di programmi simultanei:

Ipotesi:
• Semplificazione dell’ipotesi: non più di un token in un luogo.
• Una sequenza di passi atomici può essere modellata da una sequenza d’attivazione.
– Questo risolve il non determinismo dovuto all'abilitazione di diverse transizioni.
• < valore_variabile_simbolica, esecuzione_percorso, condizione_di_percorso > può essere utilizzato
per modellare lo stato simbolico dell'interprete (esecuzione_percorso è la sequenza di attivazione).

Esecuzione e test simbolici:


La condizione del percorso descrive i dati che attraversano un determinato percorso.
Utilizzare nei test:
- Percorso di selezione.
- Esecuzione simbolica.
- Sintetizza i dati che soddisfano la condizione del percorso
▪ Sarà eseguito quel percorso.

Verifica del modello:


La verifica della correttezza, in generale, è un problema indecidibile.
Il controllo del modello è una tecnica di verifica piuttosto recente, basata sul fatto che le proprietà del
sistema più interessanti diventano esprimibili (cioè: verificabili tramite algoritmi) quando il sistema è
modellato come una macchina a stati finiti.
Principi:
Descrivi un determinato sistema Software o altro, come un FSM (Automa a stati finiti):
• Esprime una determinata proprietà di interesse come una formula appropriata.
• Verifica se il comportamento del sistema soddisfa effettivamente la proprietà desiderata:
- Questo passaggio può essere eseguito automaticamente.
- Il corretto modello fornisce una dimostrazione che la proprietà detiene o fornisce un
controesempio nella forma di un caso di prova che espone l'incapacità del sistema di comportarsi in
base alla proprietà.

Proprietà e prove:
Proprietà da verificare, fornita tramite una formula (nella logica temporale).
Nell'esempio, si può provare:
• È sempre presente un calcolo che consente al processo di sinistra di accedere alla regione critica.
• Non esiste alcuna garanzia che il processo di sinistra acceda alla risorsa condivisa a meno che non la
possieda già.
Perché così tanti approcci ai test e alle analisi?
• Test vs. analisi (correttezza).
• Tecniche formali contro informali.
• Tecniche white box contro black box.
• Tecniche nel piccolo / grande.
• Tecniche completamente automatiche vs. semiautomatiche (per proprietà indecidibili).
• ecc.
Visualizza tutti questi come complementari.

Debugging:
• è un’attività di localizzazione e correzione degli errori.
• Può iniziare dopo che è stato rilevato un errore.
• L'obiettivo è colmare il divario tra un errore e un fallimento:
- Memory dump (è un processo in cui i contenuti della memoria vengono archiviati e
visualizzati in caso di crash dell’applicazione o del sistema), Punti di controllo o watchpoint
(che sono dei breakpoint speciali che interrompono l'esecuzione di un'applicazione ogni
volta che cambia il valore di una determinata espressione, senza specificare dove potrebbe
verificarsi. A differenza dei punti di interruzione (che sono specifici della linea), i punti di
controllo sono associati ai file.
- Aiuto tramite asserzioni intermedie.
Verifica di altre qualità:

Prestazioni:
• Peggior analisi dei casi:
o Focus dimostra che il tempo di risposta del sistema è limitato da alcune funzioni delle
richieste esterne, rispetto al comportamento medio.
• Deviazione standard.
• Approcci analitici vs. sperimentali.

Affidabilità:
• Esistono approcci per misurare l'affidabilità su base probabilistica, come in altri campi
dell'ingegneria.
• Sfortunatamente ci sono alcune difficoltà con questo approccio.
• L'indipendenza dai guasti non vale per il software.
• L'affidabilità riguarda la misurazione della probabilità del verificarsi di un guasto.
• I parametri significativi includono:
– numero totale medio di guasti osservati al momento t: AF (t)
– intensità di guasto: FI (t) = AF' (t)
– tempo medio di guasto al tempo t: MTTF (t) = 1/FI(t)
• Il tempo nel modello può essere tempo di esecuzione d’orologio o di calendario.

Modello di affidabilità di base:


• Presuppone che il decremento per guasto sperimentato (ovvero, la derivata rispetto al numero di guasti
rilevati) della funzione di intensità del guasto sia costante;
o ovvero FI è una funzione di AF:
FI (AF) = 𝐹𝐼0 (1 -AF / 𝐴𝐹∞ )
dove 𝐹𝐼0 è l'intensità di guasto iniziale e 𝐴𝐹∞ è il numero totale di guasti.
• Il modello si basa sull'ipotesi ottimistica secondo cui una diminuzione dei guasti è dovuta alla correzione
degli errori che sono stati fonte di guasti.

Modello logaritmico:
Presuppone, in modo più prudente, che il decremento per guasto di FI diminuisce esponenzialmente:
FI (AF) = 𝐹𝐼0 exp (- 𝜃 AF)
𝜃: parametro di decadimento dell'intensità di guasto.

Confronto tra modelli:


Verifica delle qualità soggettive:
• Considera concetti come: semplicità, riusabilità, comprensibilità ...
• La scienza del software (dovuta a Halstead) è stata un tentativo.

Scienza del software di Halstead:


• Cerca di misurare alcune qualità del software, come: livello di astrazione, costo, ecc.
• Misurando alcune quantità sul codice, come ad esempio:
– 𝜇1, numero di operatori distinti nel programma.
– 𝜇2, numero di operandi distinti nel programma.
– N1, numero di occorrenze degli operatori nel programma.
– N2, numero di occorrenze di operandi nel programma.

Metrica del codice sorgente di McCabe:


Complessità ciclomatica del grafico di controllo: –C = e -n + 2 p
- e è # bordi, n è # nodi, p è # componenti collegati.
McCabe sostiene che i moduli ben strutturati hanno C nell'intervallo 3..7, e C = 10 è un limite superiore
ragionevole per la complessità di un singolo modulo:
- Confermato da prove empiriche.

Obiettivo-domanda-metrica (GQM):
Premesse:
o Le metriche del software devono essere utilizzate per analizzare le qualità del software, non per
valutare le persone.
o La valutazione della qualità deve essere relativa al prodotto finale, ai prodotti intermedi e al
processo.
o Le metriche devono essere definite nel contesto di un paradigma di miglioramento della qualità
(QIP) completo e ben progettato.

GQM:
• Non riguarda la misurazione di una singola quantità o gruppo di quantità: ad es. Complessità
ciclomatica (Misura direttamente il numero di cammini linearmente indipendenti attraverso il grafo
di controllo di flusso).
• Un metodo che ha lo scopo di condurre da una definizione precisa degli obiettivi di misurazione
delle qualità (gli obiettivi) alle quantità (le metriche) le cui misure sono utilizzate per verificare il
raggiungimento di tali qualità.

Il metodo:
• Definisci l'obiettivo con precisione: esempio:
– Analizzare il sistema informativo allo scopo di stimare i costi dal punto di vista del gestore
nel contesto di una grande software house.
• Definire una serie adeguata di domande rivolte al raggiungimento dell'obiettivo dichiarato.
• Associare una metrica precisa a ogni domanda.

Potrebbero piacerti anche