Glossario · Fondamenti del testing
Code coverage (copertura del codice)
In inglese: Code coverage
Detto anche: copertura del codice, line coverage, branch coverage, statement coverage
Definizione
La percentuale di codice sorgente (righe, istruzioni, rami o funzioni) eseguita durante i test. Mostra cosa non è testato, non cosa è testato bene.
La code coverage (copertura del codice) misura quanta parte del codice è stata eseguita da un’esecuzione dei test. Uno strumento instrumenta il codice (JaCoCo per Java, Istanbul/nyc o la coverage di V8 per JavaScript, coverage.py per Python), esegue i test e riporta quali righe e quali rami sono stati percorsi. È una metrica white-box e si raccoglie soprattutto per i test unitari e di integrazione.
Tipi di copertura
Considera:
int shippingCost(double total, boolean isMember) {
if (total >= 100 || isMember) {
return 0;
}
return 5;
}
- Statement (line) coverage, copertura delle istruzioni: sono state eseguite entrambe le istruzioni
return? Due test,(150, false)e(20, false), danno il 100%. - Branch (decision) coverage, copertura dei rami: la
ifè stata sia vera sia falsa? Gli stessi due test danno anche qui il 100%. - Condition coverage, copertura delle condizioni: ogni sotto-condizione booleana è stata valutata sia vera sia falsa? I test sopra non hanno mai reso vero
isMember, quindi non è completa. Aggiungere(20, true)risolve. - Function coverage, copertura delle funzioni: ogni funzione è stata chiamata almeno una volta?
La branch coverage è in genere un obiettivo più utile della line coverage, perché una sola riga può nascondere più percorsi.
Cosa la coverage non ti dice
La coverage dimostra che il codice è stato eseguito, non che sia stato verificato. Questo test dà il 100% di line e branch coverage del metodo sopra e non verifica nulla:
@Test
void runsShippingCost() {
shippingCost(150, false);
shippingCost(20, false);
}
La coverage non può nemmeno rivelare codice mancante. Se il requisito dice che i membri di una certa regione pagano la spedizione e nessuno l’ha implementato, non ci sono righe da lasciare scoperte. Il mutation testing è il modo abituale per misurare se i test rilevano davvero i difetti.
Usarla bene
- Guarda le righe non coperte, non solo il numero. Un gestore di errori non testato nel percorso di pagamento conta più di un
toString()non testato. - Imponi una soglia sulla copertura del codice modificato, per esempio “il nuovo codice deve avere almeno l’80% di branch coverage”, invece di una percentuale globale che spinge a testare getter banali.
- Non considerare mai il 100% come obiettivo. Quando una metrica diventa un target, compaiono test senza asserzioni.