Che cosa è un'unità di prova, davvero? E c'è davvero una così grande dicotomia in gioco qui?
Lavoriamo in un campo in cui la lettura letteralmente un po 'oltre la fine di un buffer può causare l'arresto anomalo totale di un programma o causare un risultato totalmente inaccurato o, come evidenziato dal recente bug TLS "HeartBleed", a livello di un sistema apparentemente sicuro aperto senza produrre alcuna prova diretta del difetto.
È impossibile eliminare tutta la complessità da questi sistemi. Ma il nostro lavoro è, per quanto possibile, minimizzare e gestire quella complessità.
Un test unitario è un test che conferma, ad esempio, che una prenotazione è stata registrata correttamente in tre sistemi diversi, viene creata una voce di registro e viene inviata una conferma e-mail?
Sto per dire di 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 "caratteristica". Ma il codice alla base di tale funzione dovrebbe essere suddiviso in blocchi semplici e testabili, noti anche come "unità".
Quindi un test unitario dovrebbe avere un ambito molto limitato.
Ciò implica che il codice testato dal test unitario dovrebbe avere un ambito molto limitato.
Ciò implica inoltre che uno dei pilastri della buona progettazione è quello di scomporre il tuo problema complesso in pezzi più piccoli e monouso (per quanto possibile) che possono essere testati in un relativo isolamento l'uno dall'altro.
Ciò che si ottiene è un sistema costituito da componenti di fondazione affidabili e si sa se una di quelle unità fondamentali di codice si rompe perché hai scritto test semplici, piccoli e di portata limitata per dirti esattamente questo.
In molti casi probabilmente dovresti anche avere più test per unità. I test stessi dovrebbero essere semplici, testando uno e un solo comportamento per quanto possibile.
L'idea di un "test unitario" per testare una logica non banale, elaborata e complessa è, a mio avviso, un po 'un ossimoro.
Quindi, se quel tipo di rottura intenzionale del progetto ha avuto luogo, come potrebbe un test unitario iniziare improvvisamente a produrre falsi positivi, a meno che la funzione di base dell'unità di codice testata non sia cambiata? E se ciò è accaduto, allora è meglio credere che ci siano alcuni effetti a catena non ovvi in gioco. Il test interrotto, quello che sembra produrre un falso positivo, in realtà ti avverte che alcuni cambiamenti hanno spezzato un cerchio più ampio di dipendenze nella base di codice e devono essere esaminati e risolti.
Alcune di queste unità (molte) potrebbero dover essere testate usando oggetti finti, ma ciò non significa che devi scrivere test più complessi o elaborati.
Tornando al mio esempio inventato di un sistema di prenotazione, non puoi davvero inviare richieste a un database di prenotazione dal vivo o a un servizio di terze parti (o persino a un'istanza "dev" di esso) ogni volta che esegui il test del 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. Il verde lungo tutto il tabellone ti dice quindi che i blocchi che compongono la tua fondazione non sono rotti.
Ma la logica dei singoli test unitari rimane il più semplice possibile.