I test servono a supportare e garantire la programmazione difensiva
La programmazione difensiva protegge l'integrità del sistema in fase di runtime.
I test sono strumenti di diagnostica (per lo più statici). In fase di esecuzione, i tuoi test non sono in vista. Sono come impalcature usate per montare un alto muro di mattoni o una cupola di roccia. Non lasci parti importanti fuori dalla struttura perché hai un'impalcatura che la sostiene durante la costruzione. Hai un'impalcatura che la sostiene durante la costruzione per facilitare inserendo tutti i pezzi importanti.
MODIFICA: Un'analogia
Che dire di un'analogia con i commenti nel codice?
I commenti hanno il loro scopo, ma possono essere ridondanti o addirittura dannosi. Ad esempio, se metti la conoscenza intrinseca del codice nei commenti , quindi modifica il codice, i commenti diventano irrilevanti e dannosi nel peggiore dei casi.
Quindi affermare di mettere molta conoscenza intrinseca della propria base di codice nei test, come MethodA non può prendere nulla e l'argomento di MethodB deve essere > 0
. Quindi il codice cambia. Null va bene per A ora, e B può assumere valori fino a -10. I test esistenti ora sono funzionalmente sbagliati, ma continueranno a passare.
Sì, dovresti aggiornare i test nello stesso momento in cui aggiorni il codice. Dovresti anche aggiornare (o rimuovere) i commenti nello stesso momento in cui aggiorni il codice. Ma sappiamo tutti che queste cose non sempre accadono e che gli errori sono fatti.
I test verificano il comportamento del sistema. Questo comportamento effettivo è intrinseco al sistema stesso, non intrinseco ai test.
Cosa potrebbe andare storto?
L'obiettivo per quanto riguarda i test è di pensare a tutto ciò che potrebbe andare storto, scrivere un test che controlli il comportamento corretto, quindi creare il codice runtime in modo che passi tutti i test.
Il che significa che la programmazione difensiva è il punto .
Programmazione difensiva TDD , se i test sono completi.
Più test, guidando una programmazione più difensiva
Quando si trovano inevitabilmente bug, vengono scritti più test per modellare le condizioni che manifestano il bug. Quindi il codice è corretto, con il codice che consente di passare i test quelli e i nuovi test rimangono nella suite di test.
Una buona serie di test passerà sia argomenti validi che negativi a una funzione / metodo e si aspettano risultati coerenti. Questo, a sua volta, significa che il componente testato utilizzerà i controlli di precondizione (programmazione difensiva) per confermare gli argomenti passati ad esso.
In generale ...
Ad esempio, se un argomento nullo per una particolare procedura non è valido, almeno un test passerà un valore nullo e ci si aspetta un'eccezione / errore "argomento null non valido" di qualche tipo.
Almeno un altro test sta per passare un argomento valido , ovviamente - o passa attraverso un grande array e passa mille argomenti validi - e conferma che lo stato risultante è appropriato.
Se un test non passa quell'argomento nullo e viene schiaffeggiato con l'eccezione prevista (e quell'eccezione è stata generata perché il codice controllava in modo difensivo lo stato passato ad esso), allora null può terminare assegnato a una proprietà di una classe o sepolto in una raccolta di qualche tipo dove non dovrebbe essere.
Ciò potrebbe causare un comportamento imprevisto in alcune parti del sistema completamente diverse a cui viene passata l'istanza della classe, in alcune localizzazioni geografiche distanti dopo che il software è stato spedito . E questo è il genere di cose che in realtà stiamo cercando di evitare, vero?
Potrebbe anche essere peggio. L'istanza di classe con stato non valido può essere serializzata e archiviata, solo per causare un errore quando viene ricostituito per essere utilizzato in seguito. Geez, non lo so, forse è un sistema di controllo meccanico di qualche tipo che non può riavviarsi dopo un arresto perché non può deserializzare il proprio stato di configurazione persistente. Oppure l'istanza della classe può essere serializzata e passata a un sistema completamente diverso creato da un'altra entità, e il sistema che potrebbe bloccarsi.
Soprattutto se i programmatori di quel altro sistema non codificano in modo difensivo.