Testing software: Come valutare e migliorare la copertura dei test di unità

Testing software: Come valutare e migliorare la copertura dei test di unità

La copertura dei test di unità

Uno degli argomenti ricorrenti nella produzione dei test di unità riguarda il livello di copertura di tali test (rapporto tra le linee di codice eseguite dai test e quelle totali). In teoria, questi test dovrebbero interessare tutte le classi incluse nel sistema che si sta sviluppando (1 a 1), escludendo, ovviamente, le classi appartenenti al JDK e le librerie esterne, il cui rilascio è soggetto al superamento di uno specifico e approfondito processo di test e di QA. Anche se questo processo non sempre è infallibile, interviene un problema di ordine pratico: tentare di verificare tutte le classi del JDK o delle librerie fornite da terze parti causerebbe un dispendio di energie assolutamente improponibile.

Pertanto, giocoforza, è necessario far affidamento sui test eseguiti dai fornitori delle librerie utilizzate, ed eventualmente scrivere specifici test solo qualora ci siano fondati sospetti che determinate classi/metodi non presentino il funzionamento atteso. Infine, in ultima analisi, è necessario considerare che le classi appartenenti a librerie esterne sono comunque verificate, sebbene indirettamente, attraverso i test relativi alle classi sviluppate che ne incapsulano il comportamento.
I test di unità, quindi, dovrebbero riguardare tutte le classi prodotte. Il quesito però che resta da sciogliere è relativo a quali metodi verificare e come.

Testing software: Come valutare e migliorare la copertura dei test di unità

Nella pratica, ci si può imbattere in professionisti un po’ estremi che suggeriscono test in grado di verificare ogni possibile dettaglio, ogni possibile linea di codice del sistema. Questa strategia, contrariamente a quanto si sarebbe portati a pensare e a dispetto del relativo enorme consumo di tempo e budget, raramente risulta efficace, ed è inoltre percorribile solo in un limitato insieme di casi. La copertura esaustiva (100%) del sistema è inutile e spesso addirittura deleteria.
In primo luogo, i test di unità non verificano assolutamente i requisiti del sistema ma si occupano di verificare il funzionamento dei singoli componenti; qualora lo facessero poi, non è sempre possibile anticipare tutte le possibili combinazioni degli stimoli di input di un sistema, tanto meno è possibile ricreare tutti gli scenari di evoluzione dei thread presenti in un sistema multi-threaded da verificare, e così via. Pertanto anche nel caso in cui si riuscisse, attraverso i test di unità, a esercitare tutte le linee di codice del sistema (copertura = 100%), ciò non assicurerebbe assolutamente il corretto funzionamento dello stesso. I test di unità, sono solo un primo livello delle procedure di test del sistema, le quali devono essere pianificate attentamente anche prima dell’inizio dell’implementazione del sistema.

Coperture esaustive sono difficilmente raggiungibili anche per motivi di ordine pratico; per esempio, tutti i sistemi includono delle porzioni di codice semplicemente non raggiungibili, come catch che possono anche non verificarsi mai. Alcuni tecnici, in queste condizioni, commettono l’errore di modificare il codice al fine di rendere possibile una copertura completa. Quindi, è importante prendere atto che realizzare test esaustivi del sistema è una strategia non sempre efficace e realizzabile e assolutamente dispendiosa. Infatti, il costo di produzione iniziale e di manutenzione di test esaustivi è, nella quasi totalità dei casi, insostenibile.

Tool a supporto dei test di unità

Purtroppo, nella pratica lavorativa, accade anche spesso di imbattersi in progetti in cui i test di unità coprono una minima porzione del codice. Infatti, coperture inferiori al 60-70% del codice dovrebbero generare qualche preoccupazione al capo progetto di turno.
Anche se la produzione di questi test può sembrare un’attività eccessivamente dispendiosa e poco sostenibile, soprattutto in situazioni in cui il progetto risulti costretto da severi vincoli in termini di tempo e denaro, si tratta di una strategia che permette di realizzare più rapidamente sistemi di maggiore qualità; e la loro validità è evidenziata ad ogni iterazione/processo di refactoring. Pertanto, l’impegno profuso nella scrittura dei test di unità è ripagato, nel medio/lungo termine, in termini produzione di sistemi di qualità superiore, che, in ultima analisi, producono economie di tempo e budget.

Tutto il codice rilasciato, anche se non utilizzato, deve essere sottoposto a opportuni processi di test. Paradossalmente, anche le funzioni meno utilizzate devono essere verificate approfonditamente, proprio perché la normale pratica difficilmente potrebbe portare a individuarne i problemi.
Indipendentemente dalla strategia utilizzata per la scrittura dei test di unità, è importante misurarne il livello di copertura. A tal fine sono disponibili una serie di tool. La maggior parte di questi tool non si limita a indicare la percentuale di codice esercitata dai test, ma fornisce una serie utilissima di dati. Tra questi ci sono anche le classi/metodi non verificati, la traccia dei percorsi analizzati, etc. Pertanto, nella produzione dei test, invece di aggiungerne altri in modo randomico, è più conveniente introdurre test mirati che vadano a esercitare proprio le parti di codice non controllate da appositi test di unità. Ciò permette di evitare un’inutile ridondanza nella produzione di test, da evitare al fine di minimizzare il processo di manutenzione degli stessi test generato dalla variazione del corrispondente codice del sistema.

Pubblicato da Vito Lavecchia

Lavecchia Vito Ingegnere Informatico (Politecnico di Bari) Email: [email protected] Sito Web: https://vitolavecchia.altervista.org

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *