Originariamente TDD proveniva dal movimento agile, in cui i test venivano scritti in anticipo per garantire che ciò che si codifica rimanesse corretto, date le specifiche che erano ora ben definite nel codice di test. Appare anche come un aspetto molto importante del refactoring, in quanto quando hai modificato il tuo codice, puoi fare affidamento sui test per dimostrare che non avevi modificato il comportamento del codice.
Poi gli strumenti sono arrivati e pensavano di conoscere le informazioni sul tuo codice e potevano quindi generare stub per aiutarti a scrivere i tuoi test unitari, e penso che questo sia stato il punto in cui tutto è andato storto.
Gli stub di test sono generati da un computer che non ha idea di che cosa si stia facendo, crea semplicemente uno stub per ogni metodo perché è ciò che viene detto di fare. Ciò significa che hai un test per ogni metodo, indipendentemente dalla complessità di tale metodo o se è adatto per il test in isolamento.
Questo sta arrivando a test dalla parte sbagliata della metodologia TDD. In TDD dovresti capire che cosa deve fare il codice, e quindi produrre codice che lo consenta. Questo è auto-avverante in quanto si finisce per scrivere test che provano che il codice fa ciò che fa il codice, non ciò che dovrebbe fare. Combinato con l'auto-generazione di stub di test basati sui metodi, ti perdi molto tempo a dimostrare ogni piccolo aspetto del tuo codice che può facilmente rivelarsi sbagliato quando tutti i piccoli pezzi sono messi insieme.
Quando Fowler descrisse i test nel suo libro, si riferì a testare ogni classe con il suo metodo principale. Ha migliorato questo concetto, ma il concetto è sempre lo stesso: test l'intera classe in modo che funzioni nel suo complesso, tutti i test sono raggruppati insieme per dimostrare l'interazione di tutti quei metodi in modo che la classe possa essere riutilizzata con aspettative definite.
Penso che i toolkit di test ci abbiano reso un disservizio, ci hanno portato a pensare che il toolkit sia l'unico modo per fare le cose quando veramente, devi pensare di più per te stesso per ottenere il miglior risultato dal tuo codice. Inserire in modo cieco il codice di test negli stub di prova per pezzi piccoli significa solo che devi ripetere il tuo lavoro in un test di integrazione in ogni caso (e se hai intenzione di farlo, perché non saltare completamente la fase di test dell'unità ridondante). Significa anche che le persone sprecano molto tempo cercando di ottenere una copertura del test del 100% e molto tempo a creare grandi quantità di codice di simulazione e dati che sarebbero stati meglio spesi rendendo il codice più facile al test di integrazione (cioè se si ha tanto dipendenze dei dati, il test dell'unità potrebbe non essere l'opzione migliore)
Infine, la fragilità dei test unitari basati sui metodi mostra solo il problema. Il refactoring è progettato per essere usato con i test unitari, se i tuoi test si rompono continuamente perché stai rifattorizzando qualcosa allora si è seriamente sbagliato con l'intero approccio. Il refactoring ama creare e cancellare metodi, quindi ovviamente l'approccio basato sul metodo cieco per metodo non è ciò che era originariamente inteso.
Non ho dubbi sul fatto che molti metodi faranno dei test scritti per loro, tutti i metodi pubblici di una classe dovrebbero essere testati, ma non puoi sfuggire al concetto di testarli insieme come parte di un singolo test case. Ad esempio, se ho un metodo set e get, posso scrivere test che inseriscono i dati e controllare che i membri interni siano impostati ok, oppure posso usare ciascuno per inserire alcuni dati e poi estrarlo di nuovo per vedere se è sempre uguale e non confuso. Questo sta testando la classe, non ogni metodo in isolamento. Se il setter si affida a un metodo privato helper, allora va bene - non è necessario prendere in giro il metodo privato per assicurarsi che il setter funzioni, non se si prova l'intera classe.
Penso che la religione stia entrando in questo argomento, quindi si vede lo scisma in quello che ora è conosciuto come lo sviluppo "guidato dal comportamento" e "test-driven" - il concetto originale di test unitario era per lo sviluppo guidato dal comportamento.