"Abbiamo il 95% di code coverage." Bene. Ma il test coverage 100% è davvero l'obiettivo giusto? Cosa stiamo davvero testando? Mi è capitato di vedere suite di test con coverage altissima che non intercettavano bug critici in produzione. E suite con coverage molto basse che coprivano i flussi che contavano davvero.
La code coverage, cioè la percentuale di codice che viene eseguita mentre girano i test, rischia di diventare una metrica fine a se stessa. Un numero da mostrare nelle dashboard, da mettere nei badge del repository, da esibire nelle code review. Un numero alto non dice nulla sulla qualità dei test. Dice solo che del codice è stato eseguito durante i test.
Perché la coverage è una metrica ingannevole
Coverage misura l'esecuzione, non la verifica
Se scrivo un test che chiama una funzione ma non verifica il risultato, la coverage aumenta. La funzione è stata “coperta”: il codice è stato eseguito. Ma il test non protegge nulla. Il test passa, la coverage sale, e il bug resta lì.
I test facili alzano i numeri, quelli difficili salvano il prodotto
Testare un getter che restituisce un campo è facile. La coverage aumenta. Testare il flusso di pagamento completo con gestione degli errori, retry, e rollback è difficile. Aggiunge poca coverage, ma è il test che ti salva quando qualcosa va storto.
La tendenza naturale è scrivere molti test facili, veloci da scrivere e utili ad alzare la metrica, e pochi test difficili che richiedono setup e ragionamento. Il risultato è una suite che dà una falsa sensazione di sicurezza.
Il 100% è un obiettivo che raramente ha senso economico
Passare dal 70% all’80% è relativamente economico. Dall’80% al 90% lo sforzo cresce in modo significativo. Dal 90% al 100% lo sforzo tende a diventare sproporzionato rispetto al valore aggiunto.
Quell’ultimo tratto include casi molto rari che difficilmente vedrai in produzione. Il tempo che il team spende a inseguire il 100% è tempo che non spende a testare i flussi critici in modo più approfondito.
Quali test servono davvero
I flussi che fanno guadagnare soldi
Registrazione, login, pagamento, le azioni core del tuo prodotto. Se questi si rompono, perdi utenti e ricavi. Testali in modo approfondito: happy path, errori comuni, casi limite realistici e integrazioni reali.
Pochi test ben scritti qui valgono più di molti test su utilità secondarie.
Le integrazioni con sistemi esterni
API di terze parti, gateway di pagamento, servizi di email, storage — tutto ciò che è fuori dal tuo controllo. Qui è dove le cose tendono a rompersi più spesso: API che cambiano, timeout diversi, formati non documentati.
I test di integrazione che verificano il comportamento reale — non mock — sono tra i più preziosi che puoi avere.
I casi che ti fanno perdere soldi
Un utente viene addebitato due volte? Un ordine viene perso? I dati personali finiscono esposti? Questi scenari hanno un costo sproporzionato rispetto alla loro frequenza. Un test che previene un doppio addebito può valere più di decine di test su logica secondaria.
Identifica gli scenari più rischiosi per il tuo business e dedica particolare attenzione a testarli.
Le regressioni dopo ogni bug in produzione
Ogni bug significativo che arriva in produzione dovrebbe generare un test. Non per coverage — per prevenzione. Se è successo una volta, può succedere di nuovo. Il test riduce significativamente la probabilità che si ripresenti.
Nel tempo, questa pratica costruisce una suite che copre i problemi reali del tuo prodotto. Ed è anche ciò che rende possibile il refactoring sicuro invece della riscrittura da zero.
Cosa dire al team (e al PM)
Se gestisci un team e la coverage è diventata un obiettivo, la prima cosa da fare è smettere di fissare target numerici rigidi. Un 90% come traguardo rischia di incentivare test scritti per alzare un numero invece che per proteggere davvero il prodotto. Ha molto più senso spingere il team a coprire bene i flussi critici.
La domanda utile non è “quanta coverage abbiamo?”, ma “questo test che cosa protegge?”. Quando vengono aggiunti nuovi test, vale la pena chiedere quale scenario stanno prevenendo. Se la risposta è solo “alza la coverage”, probabilmente quel test non serve molto.
Conta anche mettere a budget il tempo per i test giusti. I test di integrazione richiedono più tempo per essere scritti e mantenuti, e proprio per questo sono i primi a saltare quando il team è sotto pressione sulle stime. Infine, la metrica che conta davvero resta un’altra: quanti bug arrivano in produzione.
Il testing è un investimento, non una cerimonia
I test sono codice. Vanno scritti, mantenuti, eseguiti, e ogni tanto riscritti. Sono un costo — un costo che si ripaga prevenendo problemi più costosi. Ma solo se testano le cose giuste. Senza una buona suite di test sui flussi critici, il deploy diventa una roulette e il team finisce per avere paura di rilasciare.
Un team con il 40% di coverage concentrata sui flussi critici è spesso in una posizione più solida di un team con il 95% distribuita uniformemente su codice che non ha impatto diretto sul business.
La coverage è un indicatore, non l’obiettivo. I test servono a proteggere il prodotto, non a riempire una metrica. L’obiettivo è un prodotto che continua a funzionare anche quando il codice cambia.
Simone Giusti
Consulente software strategico



