Metodi di specifica e verifica di software embedded per applicazioni

Transcript

Metodi di specifica e verifica di software embedded per applicazioni
Iniziativa Software Finmeccanica - Linea di Ricerca N°2
Metodi di specifica e verifica di
software embedded per
applicazioni safety-critical
Alessandro Lapadula
Dipartimento di Sistemi e Informatica, Univ. Firenze (DSI)
Selex-Galileo - A Finmeccanica Company
Sommario

Introduzione

Specifica di un caso di studio

Definizione di metriche per valutare test

Generazione automatica di test

Conclusioni
Software embedded: motivazioni

Aree di sviluppo software in Selex-Galileo:
–

Spesso i sw sono classificati safety-critical
–

radar, sistemi elettro-ottici e sonar avionici
per il ruolo svolto (es. controllo del dispositivo) e
per il campo di applicazione (es. avionico)
Testare sw safety-critical è sproporzionalmente
costoso (es. 50%-70% sul totale delle risorse)
–
tecniche (formali) che permettono di ridurre il
costo del testing sono estremamente benvenute
Software embedded: motivazioni

Aree di sviluppo software in Selex-Galileo:
–

Spesso i sw sono classificati safety-critical
–

radar, sistemi elettro-ottici e sonar avionici
per il ruolo svolto (es. controllo del dispositivo) e
per il campo di applicazione (es. avionico)
Testare sw safety-critical è sproporzionalmente
costoso (es. 50%-70% sul totale delle risorse)
–
tecniche (formali) che permettono di ridurre il
costo del testing sono estremamente benvenute
Caso di studio



Consideriamo il sistema sw di un dispositivo
elettro-ottico per l'osservazione (sorveglianza)
di zone o cose sensibili (es. confini, veicoli, etc.)
Caratteristiche principali:
–
visione diurna e notturna
–
misurazione distanze
Funzionalità esaminata:
–
Built In Test (o “bite”) è una funzione di controllo
automatico dello stato dei sensori
Caso di studio

Consideriamo il sistema sw di un dispositivo
elettro-ottico per l'osservazione (sorveglianza)
di zone o cose sensibili (es. confini, veicoli, etc.)
Camera Tv


Caratteristiche principali:
–
visione diurna e notturna
–
misurazione distanze
Laser
Infrarosso
Funzionalità esaminata:
–
Built In Test (o “bite”) è una funzione di controllo
automatico dello stato dei sensori
Caso di studio

Consideriamo il sistema sw di un dispositivo
elettro-ottico per l'osservazione (sorveglianza)
di zone o cose sensibili (es. confini, veicoli, etc.)
Camera Tv


Caratteristiche principali:
–
visione diurna e notturna
–
misurazione distanze
Laser
Infrarosso
Funzionalità esaminata:
–
Built In Test (o “bite”) è una funzione di controllo
automatico dello stato dei sensori
Formalizzazione del problema “bite”


Elementi usati nella descrizione formale
–
sid : {NONE, TVC, IR}
(dati di input)
–
timer : {0..MAX}
(timeout bite)
–
turn : {TVC, IR}
(turno di bite)
–
btvc, bir : {ON, OFF}
(dati di output)
Un esempio di funzione di output:
btvc = ON
se timer ≥ MAX con turn==TVC
bir==OFF e sid==NONE
btvc = OFF
altrimenti
Formalizzazione del problema “bite”


Elementi usati nella descrizione formale
–
sid : {NONE, TVC, IR}
(dati di input)
–
timer : {0..MAX}
(timeout bite)
–
turn : {TVC, IR}
(turno di bite)
–
btvc, bir : {ON, OFF}
(dati di output)
Un esempio di funzione di output:
btvc = ON
se timer ≥ MAX con turn==TVC
bir==OFF e sid==NONE
btvc = OFF
altrimenti
Alcune nozioni generali


Un sistema di transizione etichettato (LTS) è
una quadrupla ⟨Q, A , →, q0⟩ dove:
–
Q è un insieme di stati o configurazioni
–
A è un insieme finito di azioni
–
→ ⊆ (Q ⅹ A) ⅹ Q è una relazione di transizione
–
q0 ∊ Q è la configurazione iniziale
Sia ⟨Q, A , →, q0⟩ un LTS. Una computazione è
una sequenza finita o infinita del tipo
(q0,a0,q1), (q1,a1,q2), ..., (qi,ai,qi+1) con (qi,ai,qi+1) ∊ →
...altre nozioni generali

Data la sequenza s ∊ (A ∪ {τ})* con
–

τ detta azione invisibile o interna
s
si definisce la relazione ⇒ nel seguente modo
–
⇒ = IdQ se s=ε
–
a
τ *a τ *
⇒ = (→)
→ (→) se s=a
–
s
a0 a1 a2
⇒ = ⇒ ⇒ ⇒... se s=a0a1a2... per ogni i≥0
TAPAs (Tool for the Analysis of Process AlgebraS)


Utilizza algebre di processo (CCS+CSP) per la
specifica e la verifica di sistemi concorrenti
–
interfaccia grafica (descrive sistemi come LTS)
–
equivalence checker (bisimulation, branching, trace)
–
model checker (µ-calcolo per descrivere proprietà)
TAPAs (V0.5.7) è scaricabile all'indirizzo
http://rap.dsi.unifi.it/tapas
Specifica LTS del problema “bite”

LTS delle variabili (up to some renaming):
–
turn : {TVC, IR}
–
btvc, bir : {OFF, ON}
–
–
–
–
MAX=2
●
●
●
timer : {0..MAX}
sid : {NONE, TVC, IR}
Definizione della funzione “next”
(in forma di LTS)
Definizione della funzione “next”
(in forma di pseudo-code)
def next():
next(btvc) := case
sid==NONE & turn==TVC & timer==MAX : ON
1 : OFF
esac
next(bir) := case
sid==NONE & turn==IR & timer==MAX : ON
1 : OFF
esac
next(turn) := case
btvc==ON : IR
bir==ON : TVC
1 : turn
esac
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
1 : 0
esac
Un dettaglio della funzione “next”
next(turn) := case
btvc==ON : IR
bir==ON : TVC
1 : turn
esac
da pseudo-code a CCSP
S30-> is_btvc_on?.next[S38]
+
is_btvc_off?.next[S31]
S31-> is_bir_off?.next[S40]
+
is_bir_on?.next[S39]
da CCSP a LTS
S38-> set_turnp_ir!.next[S40]
S39-> set_turnp_tvc!.next[S40]
S40-> ...
Verifica della specifica formale

Immaginiamo di avere un documento di
Specifica dei Requisiti del Software (SRS)
dove sono definiti i seguenti tre requisiti:
R1. “In assenza prolungata di comandi (es. 5 sec)
dovrà essere interrogato lo stato dei sensori”
R2. “Un bite per un sensore potrà essere chiamato
solo se il bite sull'altro sensore è disabilitato”
R3. “Il turno-di-bite sarà assegnato in modo alterno
fra i sensori”
Validazione dei requisiti

Esempio di test manuale del requisito R1
“In assenza prolungata di comandi dovrà essere
interrogato lo stato dei sensori”
1. Si disattivano tutti comandi per i sensori
2. Si attende l'attivazione della procedura “bite”
3. Si verifica che la procedura “bite” è attiva
Validazione dei requisiti

Esempio di test manuale del requisito R1
“In assenza prolungata di comandi dovrà essere
interrogato lo stato dei sensori”
1. Si disattivano tutti comandi per i sensori
2. Si attende l'attivazione della procedura “bite”
3. Si verifica che la procedura “bite” è attiva


Come possiamo formalmente generare il test
ed adattarlo alla specifica formale?
Come possiamo stabilire formalmente se il
test è adeguato rispetto al requisito?
Requisito R1 come formula logica
“In assenza prolungata di comandi dovrà essere
interrogato lo stato dei sensori”

Come formula logica (espressa in μ-calculus)
sulle variabili btvc, bir, sid e timer:
max X.([none!]ff | [*]i[elapsed!]ff | [*](max Y.
(min Z.<btvc_on!>tt | <bir_on!>tt | <-step!>Z) &
[-step!]Y) & [*]X)
Requisito R1 come formula logica
“In assenza prolungata di comandi dovrà essere
interrogato lo stato dei sensori”

Come formula logica (espressa in μ-calculus)
sulle variabili btvc, bir, sid e timer:
max X.([none!]ff | [*]i[elapsed!]ff | [*](max Y.
(min Z.<btvc_on!>tt | <bir_on!>tt | <-step!>Z) &
[-step!]Y) & [*]X)

Formula in Computation Tree Logic (CTL):
AG(sid==NONE & timer≥MAX)→ AX(btvc==ON | bir==ON)
Alcuni possibili vantaggi


Formalizzare i requisiti permette di:
–
verificarli e “tracciarli” in modo automatico
–
individuare anticipatamente gli errori
–
sperimentare nuove tecniche di testing
–
definire nuove misure di copertura
In RTCA-DO-178B (linee-guida al processo di
sviluppo software avionico) si può leggere
–
“Test coverage of high-level requirements is
achieved” [Test objectives, Table A-7, Items 3]
Alcuni possibili vantaggi


Formalizzare i requisiti permette di:
–
verificarli e “tracciarli” in modo automatico
–
individuare anticipatamente gli errori
–
sperimentare nuove tecniche di testing
–
definire nuove misure di copertura
In RTCA-DO-178B (linee-guida al processo di
sviluppo software avionico) si può leggere
“Test coverage of high-level requirements is
achieved” [Test objectives, Table A-7, Items 3]
Verifiche formali vs testing
“Program testing can be used to show the presence
of bugs, never their absence” (Dijkstra, 1972)
Verifiche formali vs testing
“Program testing can be used to show the presence
of bugs, never their absence” (Dijkstra, 1972)



Testing come qualcosa di “poco accettabile”
Verifiche formali “esaustive” (anche per sw di
piccole dimensioni) sono raramente efficaci
Inoltre richiedono complesse tecniche di
supporto (es. abstraction o assume-guarantee proofs)
Verifiche formali vs testing
“Program testing can be used to show the presence
of bugs, never their absence” (Dijkstra, 1972)



Testing come qualcosa di “poco accettabile”
Verifiche formali “esaustive” (anche per sw di
piccole dimensioni) sono raramente efficaci
Inoltre richiedono complesse tecniche di
supporto (es. abstraction o assume-guarantee proofs)
“In molti casi il testing è il solo strumento utilizzabile
per confermare la qualità di un programma”
“Il testing non preclude l'utilizzo di tecniche formali”
Cos'è per noi un test case


Sia S = ⟨Q, A ∪ {τ}, →, q0⟩ una specifica LTS
–
un test case t ∊ A* è una sequenza di azioni e di
t
passaggi di stato tale che q0 ⇒ q
–
un test set T è un insieme finito e non vuoto di
test case
Rispetto ad un test case tradizionale:
–
un test case non descrive necessariamente
sequenze di coppie input/output
–
da un test case formale è sempre possibile
derivare test case tradizionale
Un semplice esempio di test case
R1. “In assenza prolungata di comandi dovrà
essere interrogato lo stato dei sensori”
Un semplice esempio di test case
R1. “In assenza prolungata di comandi dovrà
essere interrogato lo stato dei sensori”

Test case manuale:
1. Si disattivano tutti comandi per i sensori
2. Si attende l'attivazione della procedura “bite”
3. Si verifica che la procedura “bite” è attiva
Un semplice esempio di test case
R1. “In assenza prolungata di comandi dovrà
essere interrogato lo stato dei sensori”

Test case manuale:
1. Si disattivano tutti comandi per i sensori
2. Si attende l'attivazione della procedura “bite”
3. Si verifica che la procedura “bite” è attiva

Test case formale:
Test case in forma di specifica LTS
da test case a CCSP
q00-> none!.test[q01]
...
q05-> step!.test[q10]
q10->none!.test[q11]
...
q15-> step!.test[q20]
q20-> tvc!.test[q21]
q21-> btvc_on!.test[q22]
...
Il test è adeguato?

Tipicamente la scelta di un test set avviene in
base ad un ben determinato criterio
–

random, analisi frequenze d'uso, casi limite, ...
Alcuni criteri, detti di copertura, permettono
di definire interessanti misure di adeguatezza
Il test è adeguato?

Tipicamente la scelta di un test set avviene in
base ad un ben determinato criterio
–


random, analisi frequenze d'uso, casi limite, ...
Alcuni criteri, detti di copertura, permettono
di definire interessanti misure di adeguatezza
Un esempio è il criterio di statement coverage
Program P:
y = 7
z = y - x
if
:: (x > y) -> z = x - y
fi
Il test è adeguato?

Tipicamente la scelta di un test set avviene in
base ad un ben determinato criterio
–


random, analisi frequenze d'uso, casi limite, ...
Alcuni criteri, detti di copertura, permettono
di definire interessanti misure di adeguatezza
Un esempio è il criterio di statement coverage
Program P:
y = 7
z = y - x
if
:: (x > y) -> z = x - y
fi
TestSet1:{x=8} Cov=1
TestSet2:{x=6} Cov=2/3
Model checking come strumento
per misurare test adequacy
Test set
Specifica LTS
+
Criterio di test
LTSs
LTSs
LTSs
1
2
Formule
logiche
3
3
Model
checker
4
Misura di copertura
=
# formule soddisfatte
#totale formule
Input: S=specifica, T=test set, C=criterio di copertura
Output: misura di copertura
1. ogni test case t ∊ T viene tradotto in LTS
2. da S e C si ricava un insieme R di requisti (formule logiche)
3. si verifica se ogni formula logica è vera su almeno un t ∊ T
4. T soddisfa C se la misura di copertura è adeguata
Esempio di requisiti di copertura

Dato il criterio di state coverage:
–

Esempio di requisiti per le variabili btvc e bir
–

durante il test ogni variabile deve assumere tutti i
possibili valori del proprio domino
btvc e bir devono assumere i valori ON e OFF
Requisiti espressi in formule logiche (CTL):
{EF(btvc==ON), EF(btvc==OFF), EF(bir==ON), ...}

Espressi in forma di never claim
{AG!(btvc==OFF), AG!(btvc==ON), AG!(bir==ON),...}
Elenco completo delle formule
generate in TAPAs (state coverage)

Requisiti (formule) di state coverage per il problema “bite”
Esempio di valutazione di
un test set in TAPAs



Sia T il test set costituito dal solo test case
Nota: il test case “copre” i requisiti di alto
livello R1, R2 e R3 del problema “bite”
Purtroppo il test set T non risulta adeguato
rispetto al criterio di state coverage
Copertura dei requisiti in TAPAs

Il test soddisfa i requisiti R1, R2 e R3
Risultato di non-adeguatezza
La variabile “bir”
non è coperta
dal test

Il test non è adeguato per il criterio di state coverage
Risultato di non-adeguatezza
(never claim)
La variabile “bir”
non è coperta
dal test

Il test non è adeguato per il criterio di state coverage
Esempio di test set adeguato


Sia T' il test set costituito dal solo test case
Nota: T' è il prolungamento di T e risulta
adeguato rispetto al criterio di state coverage
Risultato di test set adeguato
Ok!

Il test è adeguato per il criterio di state coverage
Risultato di test set adeguato
Ok!

Il test è adeguato per il criterio di state coverage
Model checking come strumento
per generare test set
2
Specifica LTS
+
Criterio di test
1
Never
claims
4
2
Model
checker
3
contro-esempi
contro-esempi
contro-esempi
=
==
testset
set
test
test
set
Input: S=specifica, C= criterio di test
Output: T=test set
1. da S e C si ricava un insieme R di requisti come never claim
2. si verifica che ogni never claim è soddisfatto da S
3. se S soddisfa il never claim, si genera un contro-esempio che
sarà un test case contenuto nel test set T
4. si minimizza il test set
Generazione di test case in TAPAs*

Dati i requisiti (never claim) di state coverage
{ max X.([bir_on!]false & [-bir_on!] X)
max X.([bif_off!]false & [-bir_off!] X), ...}
si verifica la soddisfacibilità sulla specifica S
Generazione di test case in TAPAs*

Dati i requisiti (never claim) di state coverage
{ max X.([bir_on!]false & [-bir_on!] X)
max X.([bif_off!]false & [-bir_off!] X), ...}
si verifica la soddisfacibilità sulla specifica S
Formula max X.([bir_on!]false & [-bir_on!] X)
is false because S satisfies:
«none!»«btvc_off!»«bir_off!»«turn_tvc!»«inc!»«step!»
«none!»«btvc_off!»«bir_off!»«turn_tvc!»«elapsed!»«step!»
«tvc!»«btvc_on!»«bir_off!»«turn_tvc!»«elapsed!»«step!»
«none!»«btvc_off!»«bir_off!»«turn_ir!»«reset!»«step!»
«none!»«btvc_off!»«bir_off!»«turn_ir!»«inc!»«step!»
«none!»«btvc_off!»«bir_off!»«turn_ir!»«elapsed!»«step!»
«none!»«btvc_off!»«bir_on!»true
Criterio di mutation adequacy

Misura l'adeguatezza di un test set rispetto ad
un codice sorgente [DeMillo et. al. 1978]
–
il criterio richiede che i test case siano sensibili a
piccole variazioni della struttura del programma
Criterio di mutation adequacy

Misura l'adeguatezza di un test set rispetto ad
un codice sorgente [DeMillo et. al. 1978]
–

il criterio richiede che i test case siano sensibili a
piccole variazioni della struttura del programma
Breve descrizione del metodo:
–
si genera un set M di programmi alternativi
(mutanti) al programma originale P
–
su ogni P'∊ M si esegue il test set T finché
●
●
si trova un test case per il quale P e P' si comportano
diversamente (in tal caso si dice che P' viene ucciso)
oppure si esaurisce il test set T (si dice P' sopravvive)
Problema dei mutanti equivalenti

Un mutante può sopravvivere per due motivi:
–
–
test case inadeguati
●
non esercitano la porzione di P che è mutata
●
il metodo è ok - rivelano una debolezza del test set
il mutante P' è equivalente all'originale P
●
●

situazione classificata come caso raro
il metodo è ko: stabilire se due programmi sono
equivalenti in generale è un problema indecidibile
Per specifiche formali stabilire l'equivalenza
di un mutante è un problema meno critico
Specification-based
mutation analysis


[Ammann et al. 2002] definisce SM' killable
se e solo se SM ha una traccia che SM' non
possiede (←preordine basato sulle tracce)
L'adeguatezza di un test set T rispetto ad un
set M di specifiche mutanti è misurata da
#mutanti uccisi
totale mutanti - #mutanti equivalenti
Specification-based
mutation analysis


[Ammann et al. 2002] definisce SM' killable
se e solo se SM ha una traccia che SM' non
possiede (←preordine basato sulle tracce)
L'adeguatezza di un test set T rispetto ad un
set M di specifiche mutanti è misurata da
#mutanti uccisi
totale mutanti - #mutanti equivalenti
T(S), T(S')
(a)
T(S) T(S')
(b)
T(S) T(S')
(c)
T(S)
(d)
T(S')
T(S)
(e)
T(S')
Specification-based
mutation analysis


[Ammann et al. 2002] definisce SM' killable
se e solo se SM ha una traccia che SM' non
possiede (←preordine basato sulle tracce)
L'adeguatezza di un test set T rispetto ad un
set M di specifiche mutanti è misurata da
#mutanti uccisi
totale mutanti - #mutanti equivalenti
Nota: definizioni di equivalenza più fini permettono
maggiori uccisioni e quindi misure più accurate
TAPAs come strumento per
mutation analysis
Operatori di
mutazione
1
LTSs
mutanti
1
Specifica LTS
2
2
Equivalence
checker
3
Formule
logiche
4
Input: S=specifica, Op=set di operatori di mutazione
Output: misure di copertura o generazione di test
1. da S e Op si genera un insieme dei mutanti M
2. dal Equivalent Checker di TAPAs si seleziona una equivalenza
(fra quelle disponibili) per confrontare S con ogni mutante
3. dal confronto si ottengono le formule logiche che distinguono
(possibilmente) S da ogni mutante
4. le formule logiche possono essere utilizzate sia per valutare
altri test case che per generare nuovi test case
Misure di
copertura o
generazione
di test
Operatore di mutazione Var
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
1 : 0
esac
S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4]
S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4]
S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4]
S3-> inc_timer!.next[...]
S4-> reset_timer!.next[...]
Operatore Var: sostituisce una variabile con
un'altra dello stesso tipo
Operatore di mutazione Var
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
1 : 0
esac
S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4]
S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4]
S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4]
S3-> inc_timer!.next[...]
S4-> reset_timer!.next[...]
Operatore Var: sostituisce una variabile con
un'altra dello stesso tipo, per esempio
sid==NONE & bir==OFF & bir==OFF : timer++
S1-> is_bir_off?.next[S2]+is_bir_on?.next[S4]
Un caso di mutazione hard-to-kill
Pseudo-code con dead code
next(turn) := case
blrf==ON : NONE
btvc==ON : IR
bir==ON : TVC
1 : turn
esac
Codice CCSP corrispondente
S0-> is_blrf_on?.next[Sdead]
+
is_blrf_off?.next[S1]
S1-> is_btvc_on?.next[Stvc]
+
is_btvc_off?.next[S2]
...
Un caso di mutazione hard-to-kill
Pseudo-code con dead code
next(turn) := case
blrf==ON : NONE
btvc==ON : IR
bir==ON : TVC
1 : turn
esac
Operatore Var
next(turn) := case
btvc==ON : LRF
btvc==ON : IR
bir==ON : TVC
1 : turn
esac
Codice CCSP corrispondente
S0-> is_blrf_on?.next[Sdead]
+
is_blrf_off?.next[S1]
S1-> is_btvc_on?.next[Stvc]
+
is_btvc_off?.next[S2]
...
Codice CCSP corrispondente
S0-> is_btvc_on?.next[Sdead]
+
is_btvc_off?.next[S1]
S1-> is_btvc_on?.next[Stvc]
+
is_btvc_off?.next[S2]
...
Effetti della mutazione sugli LTS
Operatore Var
Uccisione del mutante in TAPAs:
1° tentativo
sys è il sistema TAPAs ottenuto
dalla specifica originale
con dead code
sys_hard è il mutante
ottenuto applicando Var
il mutante sys_hard risulta
essere non killable
Uccisione del mutante in TAPAs:
2° (definitivo) tentativo
Il sistema sys_hard
è hard-killable
deadlock
Caratterizzazione di hard-killable

Sia S = ⟨Q, A ∪ {τ}, →, q0⟩ un specifica LTS
–
q ∊ Q diverge (scritto q⇑) se esiste una sequenza
τ
infinita qi → qi+1 con i > 0 e q1=q
–
t è divergente (scritto t⇑) se esiste un prefisso t'
t'
(anche vuoto) di t tale che q0 ⇒ q e q⇑
–

t
dati Qt={q ∊ Q : q0 ⇒ q} e L ⊆ A si dice t must L
a
se ∀ q ∊ Qt q ⇒ q' implica ∃ a ∊ L e q' ⇒
Un mutante S' si dice hard-killable se non è
killable ed esiste un test case t di S tale che
–
t è divergente in S' oppure
–
per qualche L ⊆ A t must L per S ma non per S'
Peace&Love
Conclusioni


Verifiche formali “esaustive” riscontrano limiti di
applicabilità (raramente risultano efficaci)
Model/equivalence checker si dimostrano efficaci
come strumenti per valutare e generare test set
–

manca tuttora uno studio sui criteri di copertura
che tiene conto di equivalenze comportamentali
Tecniche di model extraction possono favorire la
diffusione del metodo fuori dal contesto accademico
–
minor richiesta di conoscenze particolari
–
manutenzione consistente del modello più facile
Conclusioni


Verifiche formali “esaustive” riscontrano limiti di
applicabilità (raramente risultano efficaci)
Model/equivalence checker si dimostrano efficaci
come strumenti per valutare e generare test set
–

manca tuttora uno studio sui criteri di copertura
che tiene conto di equivalenze comportamentali
Tecniche di model extraction possono favorire la
diffusione del metodo fuori dal contesto accademico
–
minor richiesta di conoscenze particolari
–
manutenzione consistente del modello più facile
–
verifica di codice automatica (nuovo seminario?)
Letture consigliate






[RTCA] Software Considerations in Airborne Systems and
Equipment Certification (DO-178B) 1992
[Zhu et al.] Software Unit Test Coverage and Adequacy.
ACM Computer Survays 1997
[Gargantini et al.] Using Model Checking to Generate Tests
from Requirements Specifications. ACM SIGSOFT 1999
[Ammann et al.] Model Checkers in Software Testing.
NIST-IR 6777 2002
[Offutt et al.] Generating Test Data from state-based
specifications. Journal of STVR 2003
[Heimdahl et al.] Testing Strategies for Model-Based
Development. NASA/CR-214307 2006
... grazie per l'attenzione
Note generali su mutation analysis



Si basa su due ipotesi:
–
il programma da testare è molto simile a quello
corretto (competent programmer assumption)
–
è molto probabile che test capaci di scoprire
semplici “piccoli” trovino anche errori più
complessi (coupling effect assumption)
Ha il vantaggio a essere facilmente automatizzabile
Lo svantaggio maggiore è che richiede notevoli
risorse di calcolo (#M~n2 per codice P con n linee)
Alcune considerazioni su TAPAs


Al momento è difficile includere TAPAs in un
ambiente di test (anche in caso di piccoli sistemi)
Motivi:
–
generazione contro-esempi (solo in caso di
equivalent checking)
–
modalità linea di comando non disponibile
–
limitata utilizzabilità dei risultati
Modello astratto dei messaggi

Variabili di input (o monitored):
TVC

SID
CMDI
CMD
LSTC
1
3
02A
0
SID
CMDI
CMD
LSTC
IR
2
8
25
1
SID
CMDI
CMD
LSTC
0
0
0
0
NONE
Variabili di output (o controlled):
btvc==ON
SID
TVSTS
IRSTS
ACK
1
1
0
0
SID
TVSTS
IRSTS
ACK
1
0
1
0
bir==ON
Caratterizzazione alterativa
Nell'esempio esiste un
test case t tale che se
L = {turn_tvc!,turn_ir!}
si ha che per S t must L
mentre non vale per S'
Operatore Var
Caratterizzazione alterativa
Nell'esempio esiste un
test case t tale che se
Operatore Var
L = {turn_tvc!,turn_ir!}
si ha che per S t must L
mentre non vale per S'
Teorema: Se S' si ottiene da S applicando uno
degli operatori di Op, S' hard-killable implica
che S' possiede un test che va in deadlock
Requisito R2 come formula logica
“Un bite per un sensore potrà essere chiamato
solo se il bite sull'altro sensore è disabilitato”

Formula μ-calculus sulle variabili btvc e bir:
max X.([btvc_on!]ff | [*]i[bir_on!]ff) & [*]X)
Requisito R2 come formula logica
“Un bite per un sensore potrà essere chiamato
solo se il bite sull'altro sensore è disabilitato”

Formula μ-calculus sulle variabili btvc e bir:
max X.([btvc_on!]ff | [*]i[bir_on!]ff) & [*]X)

Formule CTL più intuitive:
AG(btvc==ON → bir==OFF) AG(bir==ON → btvc==OFF)

Oppure nella sola formula CTL:
AG(btvc==OFF | bir==OFF)
Requisito R3 come formula logica
“Il turno-di-bite sarà assegnato in modo alterno
fra i sensori”

Formula μ-calculus usando la variabile turn:
1. max X.([btvc_on!]ff | [*]i(max Y.(min Z.
<turn_ir!>tt | <-step!>Z) & [-step!]Y) & [*]X)
2. max X.([bir_on!]ff | [*]i(max Y.(min Z.
<turn_tvc!>tt|<-step!>Z) & [-step!]Y) & [*]X)
Requisito R3 come formula logica
“Il turno-di-bite sarà assegnato in modo alterno
fra i sensori”

Formula μ-calculus usando la variabile turn:
1. max X.([btvc_on!]ff | [*]i(max Y.(min Z.
<turn_ir!>tt | <-step!>Z) & [-step!]Y) & [*]X)
2. max X.([bir_on!]ff | [*]i(max Y.(min Z.
<turn_tvc!>tt|<-step!>Z) & [-step!]Y) & [*]X)

Formule CTL più intuitive:
1. AG(btvc==ON → AX turn==IR)
2. AG(bir==ON → AX turn==TVC)
Minimizzazione di un test set



Per ridurre costi di testing è fondamentale
minimizzare le dimensioni del test set
Alcune possibili minimizzazioni si ottengono:
–
rimuovendo test duplicati
–
eliminando “test prefissi” di altri test
–
prediligendo quei contro-esempi che soddisfano
più di un requisito di copertura
Nota: quando da un test set formale si deriva
un test tradizionale si possono ottenere
ulteriori minimizzazioni (es. solo input/output)
Operatore di mutazione Const
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
1 : 0
esac
S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4]
S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4]
S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4]
S3-> inc_timer!.next[...]
S4-> reset_timer!.next[...]
Operatore Const: sostituisce una costante con
un'altra dello stesso tipo, per esempio
sid==NONE & btvc==ON & bir==OFF : timer++
S1-> is_btvc_off?.next[S4]+is_btvc_on?.next[S2]
Operatore di mutazione Neg
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
1 : 0
esac
S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4]
S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4]
S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4]
S3-> inc_timer!.next[...]
S4-> reset_timer!.next[...]
Operatore Neg: inserisce una negazione in una
espressione, per esempio
sid==NONE & !(btvc)==OFF & bir==OFF : timer++
S1-> is_btvc_off?.next[S4]+is_btvc_on?.next[S2]
Operatore di mutazione Rel
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
1 : 0
esac
S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4]
S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4]
S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4]
S3-> inc_timer!.next[...]
S4-> reset_timer!.next[...]
Operatore Rel: sostituisce un operatore con un
altro di uguale arietà, per esempio
sid==NONE | (btvc==ON & bir==OFF) : timer++
S0-> is_sid_none?.next[S3]+is_not_sid_none?.next[S1]
Operatore di mutazione Var
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
1 : 0
esac
S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4]
S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4]
S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4]
S3-> inc_timer!.next[...]
S4-> reset_timer!.next[...]
Operatore Var: sostituisce una variabile con
un'altra dello stesso tipo, per esempio
sid==NONE & bir==OFF & bir==OFF : timer++
S1-> is_bir_off?.next[S2]+is_bir_on?.next[S4]
Operatore di mutazione Bool
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
1 : 0
esac
S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4]
S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4]
S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4]
S3-> inc_timer!.next[...]
S4-> reset_timer!.next[...]
Operatore Bool: sostituisce una condizione con
true o false, per esempio
sid==NONE & true & bir==OFF : timer++
S0-> is_sid_none?.next[S2]+is_not_sid_none?.next[S4]
Definizione di misura di copertura
e accuratezza

Dati una specifica S, un test set T e un criterio
di copertura C, allora misura di copertura è
m(C, S, T) = k / N


dove N è il numero dei requisiti generati da S e
k è il numero dei requisiti soddisfatti da T
La misura m(C, S, T) sarà più accurata se si
rimuovono quei requisiti
–
impossibili (es. EF(btvc==ON & timer==1))
–
sempre veri (es. AG(turn==IR | turn==TVC))
–
duplicati (es. AG(timer ≤ 2) e AG!(timer > 2))
Alcune nozioni generali


Un sistema di transizione etichettato (LTS) è
una quadrupla ⟨Q, A , →, q0⟩ dove:
–
Q è un insieme di configurazioni
–
A è un insieme finito di azioni
–
→ ⊆ (Q ⅹ A) ⅹ Q è una relazione di transizione
–
q0 ∊ Q è la configurazione iniziale
Sia ⟨Q, A , →, q0⟩ un LTS. Una computazione è
una sequenza finita o infinita del tipo
(q0,a0,q1), (q1,a1,q2), ..., (qi,ai,qi+1) con (qi,ai,qi+1) ∊ →
...altre nozioni (±) generali


Data la sequenza s ∊ (A ∪ {τ, ρ})* con
–
τ detta azione invisibile o interna
–
ρ detta azione step o passaggio di stato
s
si definisce la relazione ⇒ nel seguente modo:
–
–
⇒ = IdQ se s=ε
a
s
– ⇒

τ
a
τ
⇒ = (→)*→ (→)* se s=a
a0 a1 a2
= ⇒ ⇒ ⇒... se s=a0a1a2... per ogni i≥0
Esempio di “passaggi di stato” di due variabili
step 1
step 2
step 3
Cos'è per noi un test case


Sia S = ⟨Q, A ∪ {τ, ρ}, →, q0⟩ una specifica LTS
–
un test case t ∊ (A ∪ {ρ})* è una sequenza di
t
azioni e di passaggi di stato tale che q0 ⇒ q
–
un test set T è un insieme finito e non vuoto di
test case
Rispetto ad un test case tradizionale:
–
un test case non descrive necessariamente
sequenze di coppie input/output
–
da un test case formale di una specifica validata è
sempre possibile derivare test case tradizionale
Risultato di non-adeguatezza
La variabile “bir”
non è coperta
dal test

Risultato di non-adeguatezza ottenuto usando lo strumento TAPAs
Risultato di test set adeguato
Ok!

Risultato di adeguatezza del test ottenuto usando lo strumento TAPAs
Caratterizzazione di hard-killable

Sia S = ⟨Q, A ∪ {τ, ρ}, →, q0⟩ un specifica LTS
–
q ∊ Q diverge (scritto q⇑) se esiste una sequenza
τ
infinita qi → qi+1 con i > 0 e q1=q
–
t è divergente (scritto t⇑) se esiste un prefisso t'
t'
(anche vuoto) di t tale che q0 ⇒ q e q⇑
–

t
dati Qt={q ∊ Q : q0 ⇒ q} e L ⊆ A si dice t must L
a
se ∀ q ∊ Qt q ⇒ q' implica ∃ a ∊ L e q' ⇒
Un mutante S' si dice hard-killable se non è
killable ma esiste un test case t di S tale che
–
t è divergente in S' oppure
–
t must L per S ma non per S' per qualche L ⊆ A
Minimizzazione di un test set


Per ridurre costi di testing è fondamentale
minimizzare le dimensioni del test set
Alcune possibili minimizzazioni si ottengono:
–
prediligendo quei contro-esempi che soddisfano
più di un requisito di copertura
–
rimuovendo test duplicati
–
eliminando “test prefissi” di altri test
Definizione della funzione “next”
(in forma di pseudo-code)
def next():
next(btvc) := case
sid==NONE & turn==TVC & timer==MAX : ON
1 : OFF
esac
next(bir) := case
sid==NONE & turn==IR & timer==MAX : ON
1 : OFF
esac
next(turn) := case
btvc==ON : IR
bir==ON : TVC
sid==LRF : LRF
1 : turn
esac
next(timer) := case
sid==NONE & btvc==OFF & bir==OFF : timer++
btvc==ON & bir==ON : -1
1 : 0
esac