Questa linea guida spiega come identificare le proposte
di test dai grafici di stato e da altre strutture che consistono principalmente in nodi collegati da archi e che
mostrano qualche elemento dei possibili flussi di controllo di un programma. L'obiettivo principale di questa verifica
è attraversare ogni arco in un test. Se non è mai stato utilizzato un arco, perché dovrebbe funzionare nel caso in cui
venga utilizzato da un cliente?
Considerare questo grafico di stato:
Fig 1: Diagramma di stato HVAC
Di seguito viene riportato un primo elenco di proposte di test:
-
Lo stato inattivo riceve un evento eccessivamente caldo
-
Lo stato inattivo riceve un evento eccessivamente freddo
-
Lo stato di avvio/raffreddamento riceve un evento di esecuzione compressore
-
Lo stato di pronto/raffreddamento riceve un evento di esecuzione ventola
-
Lo stato di esecuzione/raffreddamento riceve un evento OK
-
Lo stato di esecuzione/raffreddamento riceve un evento di errore
-
Lo stato di errore riceve un evento di errore eliminato
-
Lo stato di riscaldamento riceve un evento OK
-
Lo stato di riscaldamento riceve un evento di errore
E' possibile utilizzare tutte queste proposte di test in un singolo test o è possibile creare diversi test, con ognuno
che ne utilizza una. Come avviene con la progettazione di test, ricercare un equilibrio tra la facilità di
implementazione di molti test complessi e l'ulteriore capacità di rilevazione di difetti dei test complessi.
(Consultare "progettazione di test utilizzando l'elenco" nella pagina Concetto: Elenco di proposte di test). Se si dispone di scenari dei casi d'uso che
descrivono determinati percorsi attraverso il grafico di stato, si consiglia di privilegiare i test che intraprendono
tali percorsi.
In qualsiasi caso, i test dovrebbero controllare che tutte le azioni richieste dal grafico di stato abbiano realmente
luogo. Ad esempio, l'avviso è iniziato sulla voce nello stato di errore ed è terminato dopo l'uscita?
Il test dovrebbe, inoltre, controllare che la transizione conduca al successivo stato corretto. Questo potrebbe essere
problematico quando gli stati sono invisibili dall'esterno. L'unico modo per rilevare uno stato non corretto è inserire
le eventuali sequenze di eventi che conducono a un output non corretto. Più precisamente, sarebbe necessario costruire
una sequenza di eventi successiva, i cui risultati visibili esternamente per lo stato corretto differiscano da
quelli che la stessa sequenza provocherebbe da ogni possibile stato non corretto.
Nel suddetto esempio, come si poteva sapere che l'evento di Errore eliminato nello stato Errore conducesse
correttamente allo stato Inattivo, anziché rimanere nello stato Errore? Si potrebbe sperare che l'arresto dell'avviso
indichi che è stata effettuata una transizione, ma sarebbe meglio controllare abbassando la temperatura al punto tale
da avviare il radiatore o alzandola in modo da accendere il raffreddamento. Se si verifica un qualsiasi evento, si avrà
la certezza che la transizione era corretta. In caso contrario, è probabile che l'unità sia rimasta nello stato Errore.
Tuttavia, determinare se lo stato risultante è corretto complica la progettazione del test. Spesso, è meglio rendere la
macchina a stati esplicita e rendere gli stati visibili per i test.
Altri costrutti dei grafici di stato
I grafici di stato consistono in molto più di archi e frecce. Di seguito viene riportato un elenco di costrutti dei
grafici di stato e degli effetti che essi hanno sull'elenco di proposte di test.
Azioni di evento, azioni di immissioni e azioni di uscita
Non generano proposte di test di per se. Piuttosto, i test dovrebbero controllare che le azioni vengano eseguite nel
modo specificato. Se le azioni rappresentano programmi sostanziali, è necessario testare tali programmi. Le proposte di
test per i programmi possono essere combinate con quelle del grafico di stato, ma probabilmente è più gestibile
separarle. Prendere la decisione in base all'impegno coinvolto e alla impressione che potrebbero esistere delle
interazioni tra gli eventi. Ciò significa che, se una determinata azione su un arco non può condividere i dati con la
stessa azione su un altro arco, non vi è ragione per eseguire le due azioni nello stesso test (come avverrebbe se
fossero parte dello stesso percorso tramite un test del grafico di stato).
Condizioni di guardia
Le condizioni di guardia sono espressioni booleane. Le proposte di test per le condizioni di guardia sono ricavate nel
modo descritto in Linea guida del prodotto di lavoro: Proposte di test per valori booleani e boundary.
Nel suddetto esempio, la transizione Troppo freddo dallo stato Inattivo viene controllata con [tempo di riavvio >= 5
min]. Ciò porta a due proposte di test separate:
-
Lo stato inattivo riceve un evento eccessivamente freddo quando il tempo di riavvio è di cinque minuti (transizione
eseguita)
-
Lo stato inattivo riceve un evento eccessivamente freddo quando il tempo di riavvio è esattamente inferiore ai
cinque minuti (transizione bloccata)
In entrambi i casi, qualsiasi test che utilizza la proposta di test dovrebbe controllare che venga raggiunto lo stato
corretto.
Transizioni interne
Una transizione interna aggiunge la stessa sorta di proposte a un elenco di proposte di test, come farebbe una
transizione esterna. Essenzialmente, lo stato successivo è uguale allo stato originale. Sarebbe prudente impostare il
test in modo che le azioni di entrata e uscita dallo stato producano un effetto osservabile se sono state attivate
impropriamente.
Stati nidificati
Quando si costruiscono i test, impostarli in modo che gli eventi di entrata e di uscita dello stato composito producano
effetti osservabili. E' preferibile notare se vengono ignorati.
Sottostati simultanei
La verifica della simultaneità esula dall'ambito della verifica dello sviluppatore.
Eventi rinviati
Se si sospetta che un evento possa essere gestito in modo differente a seconda se è stato rinviato e accodato anziché
generato mentre il programma si trovava nello stato di ricezione, è possibile testare questi due casi.
Se l'evento nello stato di ricezione presenta una condizione di guardia, considerare le ramificazioni delle modifiche
alle variabili di condizione tra il tempo in cui l'evento viene generato e il tempo in cui viene ricevuto.
Se più stati possono gestire un evento rinviato, considerare la verifica del rinvio in ognuno dei possibili stati di
ricezione. Probabilmente, l'implementazione presuppone che lo stato "ovvio" gestirà l'evento.
Stati cronologici
Di seguito viene riportato un esempio di stato cronologico:
Fig 2: Esempio di stato cronologico
La transizione nello stato cronologico rappresenta tre reali transizioni e, quindi, tre proposte di test:
-
L'evento BackupUp nello stato Comando conduce allo stato Raccolta
-
L'evento BackupUp nello stato Comando conduce allo stato Copia
-
L'evento BackupUp nello stato Comando conduce allo stato Ripulitura
Stati di catena
Gli stati di catena non sembrano presentare alcuna implicazione per la progettazione dei test, con l'eccezione che
presentano più azioni che occorre controllare.
La discussione precedente è incentrata sulla verifica del fatto che l'implementazione corrisponda o meno alla
progettazione. Ma è possibile che anche la progettazione sia errata. Durante l'analisi della progettazione per rilevare
proposte di test, controllare anche due tipi di problemi:
Eventi mancanti. Il grafico di stato mostra una risposta dello stato agli eventi che il progettista
anticipato potrebbe arrivare in tale stato. Può capitare che i progettisti trascurino gli eventi. Ad esempio, in
questo grafico di stato (ripetuto dall'inizio della pagina), probabilmente il progettista ha trascurato che potrebbe
verificarsi un errore nel sottostato Pronto del Raffreddamento e non solo quando la ventola è in esecuzione.
Fig 3: Diagramma di stato HVAC
Per tale ragione, è bene chiedersi, per ogni stato, se qualcuno degli eventi che si applica ad altri stati potrebbe
applicarsi anche a quello corrente. se si rileva che per uno è così, correggere la progettazione.
Condizioni di guardia incomplete o mancanti. In modo simile, probabilmente, le condizioni di guardia su una
transizione suggeriranno le condizioni di guardia sulle altre. Ad esempio, il grafico di stato precedente si prende
cura di non riavviare il radiatore troppo frequentemente, ma tale restrizione non è presente nel sistema di
raffreddamento. Dovrebbe esserci?
E' anche possibile che le variabili utilizzate sulla condizione di guardia suggeriscano che altre condizioni di guardia
sono troppo semplici.
La verifica di ogni arco in un grafico non è affatto una verifica completa. Ad esempio, si supponga che lo stato di
avvio inizializzi una variabile su 0, lo stato Setter la imposta su 5 e lo stato Divider la divide in 100
(100/variabile). Se, dallo stato di avvio a Divider, esiste un percorso che non passa per Setter, si ottiene
un'eccezione di divisione per zero. Se il grafico di stato presenta diversi stati, nell'utilizzo di ogni arco potrebbe
mancare tale percorso.
Ad eccezione dei grafici di stato estremamente semplici, la verifica di ogni percorso è irrealizzabile. In pratica, i
test complessi che corrispondono a scenari dei casi d'uso sono spesso sufficienti. Per ottenere test più validi, è
necessario un percorso per ogni stato in cui a ogni dato utilizzato viene assegnato un valore.
|