Che test un unità , davvero? E c'è davvero una grossa dicotomia in gioco qui?
Lavoriamo in un campo in cui la lettura letteralmente un po 'oltre la fine di un buffer può bloccare completamente un programma o causare un risultato totalmente impreciso, o come evidenziato dal recente bug TLS "HeartBleed" sistema sicuro spalancato senza produrre alcuna prova diretta del difetto.
È impossibile eliminare tutta la complessità da questi sistemi. Ma il nostro compito è, per quanto possibile, minimizzare e gestire tale complessità.
Un'unità prova un test che conferma, ad esempio, che una prenotazione viene registrata con successo in tre sistemi diversi, che viene creata una voce di registro e viene inviata una conferma via email?
Ho intenzione di dire no . Questo è un test di integrazione . E quelli sicuramente hanno il loro posto, ma sono anche un argomento diverso.
Un test di integrazione funziona per confermare la funzione complessiva di un'intera "funzione". Ma il codice che sta dietro questa caratteristica dovrebbe essere scomposto in semplici blocchi testabili, chiamati anche "unità".
Quindi un test unitario dovrebbe avere un ambito molto limitato.
Che implica che il codice testato da il test dell'unità dovrebbe avere un ambito molto limitato.
Il che implica inoltre che uno dei pilastri del buon design è quello di rompere il tuo complesso problema in pezzi più piccoli, per un singolo scopo (nella misura del possibile) che possono essere testati in un relativo isolamento l'uno dall'altro.
Ciò che si ottiene è un sistema costituito da componenti di base affidabili, e si sa se una qualsiasi di queste unità fondamentali di codice si interrompe perché hai scritto test semplici, di portata limitata per dirti esattamente quello.
In molti casi dovresti anche probabilmente avere più test per unità. Gli stessi test dovrebbero essere semplici, testando un solo e unico comportamento nella misura del possibile.
La nozione di un "test unitario" per testare una logica complessa non complessa, è, credo, un po 'un ossimoro.
Quindi, se questo tipo di rottura deliberata del progetto ha avuto luogo, allora come nel mondo un test unitario potrebbe improvvisamente iniziare a produrre falsi positivi, a meno che la funzione di base dell'unità di codice testata sia cambiata ? E se che è successo, allora è meglio che ci siano alcuni effetti a catena non ovvi in gioco. Il tuo test non funzionante, quello che sembra produrre un falso positivo, ti avverte in realtà che alcuni cambiamenti hanno infranto una più ampia cerchia di dipendenze nel codice base, e devono essere esaminati e risolti.
Alcune di queste unità (molte di queste) potrebbero aver bisogno di essere testate usando oggetti finti, ma ciò non significa che devi scrivere test più complessi o elaborati.
Tornando al mio esempio forzato di un sistema di prenotazione, non puoi davvero inviare richieste a un database di prenotazione in diretta oa un servizio di terze parti (o persino a un'istanza di "dev") ogni volta che unità verifica il tuo codice.
Quindi usi mock che presentano lo stesso contratto di interfaccia. I test possono quindi validare il comportamento di un pezzo di codice relativamente piccolo e deterministico. Verde in fondo al tabellone poi ti dice che i blocchi che costituiscono la tua fondazione non sono infranti.
Ma la logica dei singoli test di unità rimane la più semplice possibile.