Corso ISTQB — Modulo 6: Tecniche white-box ed esperienziali, e approcci collaborativi
Nel modulo precedente hai imparato a derivare casi di test guardando il software “da fuori”, cioè dalle sue specifiche e dal suo comportamento, senza preoccuparti di come fosse scritto il codice. In questo modulo cambiamo prospettiva due volte. Prima apriamo il cofano e osserviamo la struttura interna del software (tecniche white-box, syllabus §4.3). Poi facciamo l’opposto: ci affidiamo all’intuito, all’esperienza e alla creatività di chi prova il software (tecniche basate sull’esperienza, syllabus §4.4). Infine vediamo come testing e sviluppo possano collaborare fin dall’inizio, concordando i criteri di verifica prima di programmare (approcci collaborativi, syllabus §4.5).
All’esame CTFL questi argomenti pesano in modo diverso. Sulle tecniche white-box ti viene quasi sempre chiesto di calcolare la copertura, oppure di ragionare sulla relazione tra copertura delle istruzioni e copertura dei rami. Sulle tecniche esperienziali e collaborative le domande sono più concettuali: riconoscere la definizione corretta, distinguere un approccio dall’altro, capire quando conviene usarli. Tienilo a mente mentre studi.
Cosa significa “white-box” e perché conta
Una tecnica si dice white-box (talvolta detta “structure-based”, basata sulla struttura) quando i casi di test si ricavano dalla struttura interna del software: il codice sorgente, il flusso di controllo, l’architettura. La base di test non è più “cosa deve fare il programma” ma “com’è fatto al suo interno”.
L’idea guida è la copertura (coverage): una misura, espressa in percentuale, di quanta parte di un determinato elemento strutturale è stata effettivamente esercitata dai test. Se ho eseguito 8 istruzioni su 10, la mia copertura delle istruzioni è dell’80%. La copertura serve a due cose: dirti quanto sei andato a fondo e suggerirti dove mancano ancora prove. Attenzione però: il 100% di copertura non significa “zero difetti”, significa soltanto che ogni elemento di quel tipo è stato eseguito almeno una volta.
A livello Foundation, il syllabus v4.0 richiede due tecniche white-box: la copertura delle istruzioni (statement testing) e la copertura dei rami (branch testing).
Copertura delle istruzioni (statement testing)
Un’istruzione è una singola unità eseguibile di codice (un’assegnazione, una chiamata, un return). La copertura delle istruzioni misura quante di queste istruzioni vengono effettivamente eseguite durante i test, rispetto al totale delle istruzioni eseguibili.
La formula è semplice:
- Copertura istruzioni = (istruzioni eseguite / istruzioni totali) × 100
Esempio concreto. Immagina una piccola funzione che calcola lo sconto in un negozio online di scarpe sportive:
- riga 1: leggi l’importo del carrello
- riga 2: se l’importo supera 100 euro
- riga 3: applica uno sconto del 10%
- riga 4: stampa il totale
Se eseguo un solo test con un carrello da 150 euro, attraverso le righe 1, 2, 3 e 4: tutte e quattro le istruzioni vengono eseguite, quindi raggiungo il 100% di copertura delle istruzioni con un unico caso di test. Sembra rassicurante, ma c’è un problema: non ho mai provato il caso del carrello sotto i 100 euro, in cui lo sconto non si applica. Su questo limite torniamo subito.
Copertura dei rami (branch testing)
Una decisione è un punto del codice in cui il flusso si biforca: un if, un while, un for, un case. Da una decisione partono più rami (branch): per esempio un costrutto if con esito vero e con esito falso genera due rami. La copertura dei rami misura quanti di questi rami sono stati percorsi dai test.
- Copertura dei rami = (rami eseguiti / rami totali) × 100
Riprendiamo l’esempio dello sconto. C’è una sola decisione (l’if alla riga 2), con due rami: quello in cui “importo > 100” è vero (si applica lo sconto) e quello in cui è falso (si salta lo sconto). Il mio unico test da 150 euro copre solo il ramo “vero”. Per raggiungere il 100% di copertura dei rami mi serve un secondo test, per esempio un carrello da 60 euro, che percorra il ramo “falso”. Solo allora avrò esercitato entrambi i rami.
È proprio il difetto che la sola copertura delle istruzioni non aveva fatto emergere: il ramo “nessuno sconto” non era mai stato percorso, eppure le istruzioni risultavano coperte al 100%.
Una nota terminologica utile: nelle versioni precedenti del syllabus si parlava di “decision testing”, mentre la v4.0 adotta il termine “branch testing”. In molti casi pratici, e per i quesiti d’esame a livello Foundation, le due nozioni portano agli stessi calcoli di copertura; il punto importante è che ogni decisione richiede di percorrere tutti i suoi rami.
La relazione tra istruzioni e rami
È il punto più “gettonato” all’esame, quindi fissalo bene. La relazione è gerarchica:
- Il 100% di copertura dei rami garantisce sempre il 100% di copertura delle istruzioni. Se hai percorso ogni ramo di ogni decisione, hai necessariamente eseguito anche tutte le istruzioni raggiungibili del codice.
- Il contrario non vale: puoi avere il 100% delle istruzioni e non avere il 100% dei rami (come nel nostro esempio con il solo test da 150 euro).
In altre parole, la copertura dei rami è una misura più forte, più “esigente”, di quella delle istruzioni. Raggiungere un livello alto di copertura dei rami richiede di norma più casi di test, ma offre più garanzie, perché obbliga a provare anche i percorsi “negativi” che spesso nascondono i difetti.
Il valore del white-box
Perché vale la pena testare guardando la struttura interna? Alcuni motivi pratici (syllabus §4.3.3):
- Mette in luce porzioni di codice mai eseguite dai test funzionali: rami dimenticati, gestioni di errore mai provate, codice “morto”.
- Fornisce una misura oggettiva e quantificabile della profondità del testing: invece di dire “abbiamo testato abbastanza”, puoi dire “abbiamo raggiunto il 90% di copertura dei rami”.
- Trova difetti che le tecniche black-box possono ignorare, perché esercita comportamenti che le specifiche non descrivono esplicitamente ma che il codice implementa.
Il limite, da ricordare per onestà intellettuale (e per l’esame): il white-box verifica ciò che il codice fa, non ciò che avrebbe dovuto fare. Se una funzionalità richiesta non è stata scritta affatto, nessuna copertura del codice esistente la farà emergere. Per questo le tecniche white-box e black-box sono complementari, non alternative.
Tecniche basate sull’esperienza
Le tecniche esperienziali (syllabus §4.4) non derivano i test da un documento formale o dalla struttura del codice, ma dalla conoscenza, intuizione ed esperienza di chi prova il software: dove i difetti tendono a nascondersi, quali errori commettono di solito gli sviluppatori, come si rompono i sistemi simili. Sono molto efficaci come complemento alle tecniche sistematiche, ma la loro qualità dipende fortemente dalla persona che le applica; per questo risultano difficili da rendere ripetibili e da misurare in termini di copertura.
Error guessing (previsione degli errori)
L’error guessing consiste nell’immaginare quali errori, difetti e malfunzionamenti sono più probabili, e nel costruire test mirati a stanarli. Il tester si chiede: “Dove è più facile che si rompa? Cosa avrà trascurato chi ha scritto questo codice?”.
Esempio: in un modulo di registrazione utenti, l’esperienza suggerisce di provare un nome con caratteri speciali ed emoji, una data di nascita nel futuro, una password lunghissima, un’email priva della chiocciola, l’invio del modulo due volte in rapida successione. Tutti casi che le specifiche magari non menzionano, ma che chi ha esperienza sa essere fonte di guai. Spesso ci si aiuta con liste di difetti tipici raccolte in progetti passati (fault attack o defect lists), per rendere l’attività un po’ meno dipendente dalla sola memoria del singolo.
Testing esplorativo
Nel testing esplorativo progettazione, esecuzione e apprendimento avvengono contemporaneamente: chi prova il software lo esplora, e ciò che scopre in un dato momento orienta cosa proverà subito dopo. Non si parte da casi di test scritti in anticipo, ma da obiettivi.
Per evitare che diventi un “cliccare a caso”, lo si struttura spesso in test charter: brevi mandati che fissano un obiettivo, un’area da esplorare e un tempo limite (per esempio “esplora il carrello per 45 minuti cercando problemi nei calcoli di sconto”). Questa forma organizzata si chiama session-based test management. Il testing esplorativo è particolarmente utile quando le specifiche sono scarse o cambiano in fretta, oppure quando serve un riscontro rapido su una nuova funzionalità.
Testing basato su checklist
Nel testing basato su checklist chi prova il software segue una lista di controlli, condizioni o regole da verificare, costruita su esperienza, standard o requisiti ricorrenti. La checklist è di alto livello e lascia spazio al giudizio del tester su come verificare ciascun punto.
Esempio: una checklist di usabilità per un’app mobile potrebbe contenere voci come “i pulsanti sono raggiungibili con il pollice”, “i messaggi di errore sono comprensibili”, “l’app reagisce alla rotazione dello schermo”, “i campi obbligatori sono segnalati”. Va aggiornata nel tempo, altrimenti, col succedersi dei progetti, diventa obsoleta e perde valore.
Approcci collaborativi: testing e sviluppo insieme
L’ultima parte del modulo (syllabus §4.5) sposta il focus dalla tecnica al modo di lavorare. Negli approcci collaborativi, tipici dei contesti agili, si cerca di chiarire cosa deve fare il software e come verificarlo prima di scrivere il codice, coinvolgendo insieme business, sviluppo e testing (i cosiddetti “tre amici”, o three amigos).
User story e criteri di accettazione
Una user story è una descrizione breve di una funzionalità dal punto di vista di chi la userà, scritta in un linguaggio comprensibile a tutti gli stakeholder. Una formulazione frequente è: “Come tipo di utente, voglio obiettivo, così da beneficio“. Esempio: “Come cliente, voglio salvare la mia carta di pagamento, così da non doverla reinserire ogni volta”.
Una user story ben fatta non basta da sola: ha bisogno di criteri di accettazione (acceptance criteria), cioè le condizioni concrete e verificabili che devono essere soddisfatte perché la funzionalità sia considerata “completata”. Sono il confine tra “fatto” e “non ancora fatto”. Per la nostra story potrebbero essere: “la carta salvata è mostrata mascherata (solo le ultime 4 cifre)”, “l’utente può eliminare una carta salvata”, “i dati della carta sono cifrati”. I criteri di accettazione diventano la base per i test di accettazione.
Un acronimo utile da ricordare è INVEST, che riassume le caratteristiche di una buona user story: Independent, Negotiable, Valuable, Estimable, Small, Testable. L’ultima, “Testable” (verificabile), è quella che lega direttamente la story al lavoro del tester: se una story non si può verificare, manca qualcosa.
ATDD (Acceptance Test-Driven Development)
L’ATDD è un approccio collaborativo in cui i test di accettazione vengono definiti durante l’analisi dei requisiti, prima ancora di iniziare a sviluppare. Business, sviluppatori e tester si confrontano sulla user story e ne ricavano esempi concreti del comportamento atteso; questi esempi vengono poi trasformati in test di accettazione che guidano lo sviluppo.
I vantaggi: si chiariscono i malintesi prima di scrivere il codice (quando correggere costa poco), i requisiti diventano automaticamente verificabili e tutti condividono la stessa idea di “completato”. Da non confondere con il TDD: il TDD è una pratica dello sviluppatore, centrata sui test di unità del codice; l’ATDD è collaborativo e centrato sul comportamento atteso dal punto di vista dell’utente o del business. L’esame ama questa distinzione.
Termini chiave
- Tecnica white-box = tecnica che deriva i casi di test dalla struttura interna del software (codice, flusso di controllo).
- Copertura (coverage) = percentuale di un determinato elemento strutturale che è stato esercitato dai test.
- Copertura delle istruzioni = percentuale di istruzioni eseguibili effettivamente eseguite dai test.
- Decisione = punto del codice in cui il flusso si biforca (if, while, for, case), da cui partono più rami.
- Copertura dei rami (branch) = percentuale di rami delle decisioni effettivamente percorsi dai test.
- Error guessing = tecnica esperienziale in cui si progettano test prevedendo i difetti più probabili.
- Testing esplorativo = approccio in cui si progetta, si esegue e si apprende contemporaneamente, spesso guidato da test charter.
- Test charter = breve mandato che fissa obiettivo, area e durata di una sessione esplorativa.
- Testing basato su checklist = tecnica che usa una lista di controlli derivata dall’esperienza per guidare il testing.
- User story = descrizione breve di una funzionalità dal punto di vista dell’utente, completata dai criteri di accettazione.
- Criteri di accettazione = condizioni verificabili che definiscono quando una funzionalità è considerata completata.
- ATDD = approccio collaborativo in cui i test di accettazione si definiscono durante l’analisi, prima dello sviluppo.
Errori comuni all’esame
- Invertire la relazione tra le coperture. Si ricorda solo che “sono collegate” e si sbaglia il verso. Fissa la regola: il 100% dei rami implica il 100% delle istruzioni, mai il contrario.
- Credere che il 100% di copertura significhi software senza difetti. La copertura misura ciò che è stato eseguito, non l’assenza di bug né la correttezza rispetto a requisiti mancanti.
- Confondere ATDD e TDD. TDD = pratica dello sviluppatore, test di unità; ATDD = collaborativo, test di accettazione dal punto di vista dell’utente.
- Pensare che il testing esplorativo sia non strutturato. È guidato da charter e obiettivi: “esplorativo” non vuol dire “casuale o senza disciplina”.
- Classificare le tecniche esperienziali come white-box o black-box. Costituiscono una terza categoria a sé, basata sulla conoscenza di chi prova il software.
- Considerare error guessing e testing basato su checklist la stessa cosa. Il primo punta a prevedere i difetti probabili; il secondo segue una lista predefinita di controlli.
- Trattare user story e criteri di accettazione come sinonimi. La story descrive il bisogno; i criteri di accettazione definiscono in modo verificabile quando è soddisfatto.
In sintesi
- Le tecniche white-box derivano i test dalla struttura del codice; la copertura ne misura la profondità in percentuale, ma non garantisce l’assenza di difetti.
- Copertura delle istruzioni = istruzioni eseguite; copertura dei rami = rami percorsi. Il 100% dei rami implica il 100% delle istruzioni, non viceversa: la copertura dei rami è la più forte.
- Il valore del white-box sta nel rivelare codice mai eseguito e nel fornire misure oggettive, complementari (non sostitutive) al black-box.
- Le tecniche esperienziali — error guessing, testing esplorativo, testing basato su checklist — sfruttano la conoscenza di chi prova il software e completano le tecniche sistematiche.
- Gli approcci collaborativi (user story, criteri di accettazione, ATDD) definiscono cosa verificare prima di sviluppare, riducendo i malintesi quando costa poco correggerli.
- Ricorda INVEST per le user story e la distinzione netta tra ATDD (accettazione, collaborativo) e TDD (unità, sviluppatore).