Il primo scopo di una suite di test è verificare che il codice funzioni come previsto.
Ma cosa succede se qualcosa va storto? Il secondo scopo è quello di rendere più facile per il programmatore capire facilmente cosa è andato storto e dove.
Diagnostica migliore
Quando una semplice asserzione fallisce, tutto ciò che viene detto è che non ha funzionato, nessun motivo per cui. Bene, almeno ci viene dato il numero di riga dell'asserzione fallita. Esempio di un quadro di prova immaginario:
ERROR: assertion failed
in test.js line 165:
assert(result === expected);
Questo rende complicato il debug del problema - dobbiamo guardare il codice sorgente per il test, registrare i valori prima dell'asserzione, rieseguire tutto, sperare che il problema sia ancora presente e quindi iniziare a cercare il bug.
Quando la funzione di asserzione non ha un valore booleano ma due valori da confrontare, può fornire messaggi di errore molto migliori:
ERROR: assertion failed
in test.js line 165:
assertEquals(result, expected);
got: [42, 42, 42]
expected: [41, 42, 43]
Spesso, non dobbiamo nemmeno più esaminare il test e possiamo immediatamente capire il problema dai valori registrati.
Poiché l'uguaglianza non è l'unica relazione che potrebbe essere testata, ora abbiamo bisogno di varie funzioni assert*
. Per esempio. assertNotEquals(result, otherValue)
, assertThrows(function)
, assertMatches(result, expectedRegex)
, ....
Organizzazione di test migliore
Il prossimo vantaggio di un framework di test è che ci aiuta a organizzare i nostri test e semplifica l'elaborazione dei risultati del test.
Un singolo caso di test che verifica tutto è problematico, perché ciò rende difficile scoprire i test per un particolare modulo o funzione nel nostro codice sorgente. Preferisco una descrizione / organizzazione in stile RSpec:
describe("functionA", () => {
it("sums the values", () => {
assertEquals(functionA(2, 3, 4), 9);
});
it("throws for negative numbers", () => {
assertThrows(() => functionA(2, 3, -1));
});
});
Un messaggio di errore ora può spiegare chiaramente cosa stavamo testando:
test "functionA throws for negative numbers" failed:
did not throw
in test.js line 165:
assertThrows(() => functionA(2, 3, -1));
Rapporti sui test migliori
Ancora più importante, il test runner è ora responsabile dell'esecuzione delle singole funzioni di test. Se un'affermazione fallisce, i test non correlati verranno comunque eseguiti. Ciò consente di sapere quanti test hanno fallito in totale, ad es. "FAILED 3 di 367 test" o "SUPERATO tutti i 367 test". Ciò ti aiuta a essere certo che tutti i tuoi test siano effettivamente eseguiti.
Alcuni test runner rendono più chiaro il loro output visualizzando solo i dettagli dei casi di test falliti e evidenziando parti importanti con i colori.
Inoltre, un corridore di test può scrivere i risultati del test in un formato leggibile dalla macchina, ad es. TAP o XML. Questi possono quindi essere visualizzati ed elaborati da IDE o strumenti di integrazione continua.