2010-07-18 21 views
11

Ho appena acquistato The Art of Unit Testing da Amazon. Sono piuttosto serio riguardo alla comprensione di TDD, quindi ti assicuro che questa è una domanda vera.Cercando di acquisire confidenza con i vantaggi del TDD

Ma mi sento come se fossi costantemente sul punto di trovare una giustificazione per rinunciarvi.

Ho intenzione di interpretare l'avvocato del diavolo qui e di tentare di abbattere i presunti benefici del TDD nella speranza che qualcuno possa dimostrarmi sbagliato e aiutarmi a essere più fiducioso nelle sue virtù. Penso che mi manchi qualcosa, ma non riesco a capire cosa.

1. TDD per ridurre i bug

Questo often-cited blog post dice che i test di unità sono strumenti di progettazione e non di bug cattura:

Nella mia esperienza, i test di unità non sono un modo efficace per trova bug o rileva regressioni.

...

TDD è un modo robusto di progettare componenti software (“unità”) interattivamente in modo che il loro comportamento è specificata attraverso test unitari. Questo è tutto!

Ha senso. I casi limite saranno sempre presenti, e troverai solo i bug superficiali, che sono quelli che troverai non appena esegui la tua app. È ancora necessario eseguire i test di integrazione corretti dopo aver completato una buona parte del software.

Abbastanza corretto, ridurre i bug non è l'unica cosa che TDD dovrebbe aiutare.

2. TDD come un paradigma di progettazione

Questo è probabilmente uno dei grandi. TDD è un paradigma di progettazione che ti aiuta (o ti costringe) a rendere il tuo codice più composable.

Ma la componibilità è una qualità moltiplicabile; lo stile di programmazione funzionale, ad esempio, rende anche il codice abbastanza componibile. Naturalmente, è difficile scrivere un'applicazione su larga scala interamente in stile funzionale, ma ci sono alcuni schemi di compromesso che è possibile seguire per mantenere la componibilità.

Se si inizia con un progetto funzionale altamente modulare e quindi si aggiungono attentamente lo stato e l'IO al proprio codice secondo necessità, si otterranno gli stessi motivi che TDD incoraggia.

Ad esempio, per eseguire la business logic su un database, il codice IO può essere isolato in una funzione che esegue le attività "monadiche" di accesso al database e lo inoltra come argomento alla funzione responsabile della logica di business . Quello sarebbe il modo funzionale per farlo.

Naturalmente, questo è un po 'goffo, così, invece, potremmo lanciare un sottoinsieme del codice IO del database in una classe e darlo a un oggetto contenente la logica aziendale pertinente. È la stessa identica cosa, un adattamento del modo funzionale di fare le cose, e si riferisce al modello di repository.

So che probabilmente questo mi farà guadagnare una pessima fustigazione, ma spesso, non posso fare a meno di pensare che TDD compensi solo alcune delle cattive abitudini che OOP può incoraggiare - quelle che possono essere evitato con un po 'di ispirazione dallo stile funzionale.

3. TDD come documentazione

TDD si dice per servire come documentazione, ma serve solo come documentazione per i coetanei; il consumatore richiede ancora la documentazione di testo.

Ovviamente, un metodo TDD potrebbe servire come base per il codice di esempio, ma i test generalmente contengono un certo grado di mock che non dovrebbero essere nel codice di esempio, e di solito sono abbastanza elaborati in modo che possano essere valutati per l'uguaglianza contro il risultato atteso.

Un buon test unitario descriverà nel suo metodo il comportamento esatto che si sta verificando e il test non verificherà né più né meno di tale comportamento.

Quindi, direi, il vostro tempo potrebbe essere meglio speso per lucidare la vostra documentazione. Diamine, perché non fare solo la documentazione prima di tutto e chiamarla Design guidato dalla documentazione?

4. TDD per i test di regressione

E 'citata in quel post sopra che TDD non è molto utile per rilevare regressioni. Questo è, naturalmente, perché i casi limite non ovvi sono quelli che rovinano sempre quando si modifica un codice.

Ciò che potrebbe essere anche da notare su questo argomento è che è probabile che la maggior parte del codice rimanga invariata per un tempo piuttosto lungo. Quindi, non avrebbe più senso scrivere test unitari in base alle necessità, ogni volta che il codice viene modificato, mantenendo il vecchio codice e confrontando i suoi risultati con quelli della nuova funzione?

+1

"quelli che possono essere evitati con un po 'di ispirazione dallo stile funzionale." Quasi d'accordo ... TDD incoraggia uno stile di codifica più vicino al modello di attore, che è una specie di inverso dello stile funzionale (è un modello push rispetto al tiro della codifica funzionale) – kyoryu

+0

Interessante ... dovrei esaminare il modello dell'attore . Questo potrebbe contenere la risposta che sto cercando! –

+0

Vale la pena notare che Alan Kay è stato citato dicendo che si rammarica di usare il termine "orientato agli oggetti" e desidera che abbia usato "orientato ai messaggi". TDD ti spinge verso uno stile orientato ai messaggi (che è il cuore del modello di attore, o dei processi sequenziali comunicanti, o ...) – kyoryu

risposta

3

Credo che il vantaggio di TDD sia che in realtà scrivi i test in quanto sono più interessanti quando sono un obiettivo che devi raggiungere, (creare codice per superare i test), piuttosto che un lavoro che devi fare in seguito .

Inoltre, ti mette nella mente dell'utente. Devi pensare "quindi cosa l'utente ha bisogno del mio metodo per fare" o qualsiasi altra cosa, piuttosto che "Spero che il mio metodo abbia raggiunto ciò che avrebbe dovuto fare". In questo modo, può anche aiutare a ridurre i bug.

+0

Non sono sicuro che TDD non sia eccessivo per questo scopo, ma questo sembra essere la motivazione più sensata per TDD. –

+0

Beh, posso anche avere una lista di cose da fare per quello ... –

+0

Sì, questa è la cosa, ecco perché dopo quasi un anno non sono ancora convinto. –

0

TDD fornisce anche il codice che è completamente coperto da test unitari automatizzati. Questo è semplicemente perché non viene scritto alcun codice fino a quando non è necessario eseguire un passaggio di prova dell'unità in errore.

1

Volevo solo evidenziare:
test TDD non sono test unitari

"Lo scopo di un test di unità è quello di testare un'unità di codice in isolamento."
"Un test TDD, a differenza di un test di unità, potrebbe testare più di una singola unità di codice alla volta." I test TDD sono più test di interazione ....

da molto buono post sul blog di Stephen Walter TDD Tests are not Unit Tests

5

In termini di design, uno dei principali benifit del TDD non si è visto è che spinge il design ad essere appena sufficiente.Sai cosa dicono che l'ingegnere vede il vetro due volte più grande di quanto dovrebbe essere. La sovraimpressione nel software può essere un grosso problema. Trovo che il 90% del tempo TDD abbia forzato la giusta ballata di astrazione per supportare l'estensione successiva del codice. TDD non è magico, ci vuole anche il programmatore per farlo, ma è una parte importante del toolkit.

Penso che ci sia troppa TDD in isolamento nella tua lista. Che dire del refactoring? Penso che uno dei principali vantaggi del test sia che blocca il comportamento, in modo che quando si refactoring si può essere sicuri che non è cambiato nulla, che a sua volta può renderti sicuro sul refactoring. E non c'è niente come un design che nasce dall'esperienza piuttosto che da una lavagna (anche se il design della lavagna di alto livello è ancora molto importante).

Inoltre, si scrive: "Quindi, non avrebbe più senso scrivere test di unità in base alle necessità, ogni volta che il codice viene modificato, mantenendo il vecchio codice e confrontando i risultati con quelli della nuova funzione?" Il codice che viene scritto senza test unitari è spesso non verificabile, soprattutto se interagisce con servizi esterni come un database, un gestore transazioni, un toolkit GUI o un servizio web. Aggiungendoli più tardi non succederà.

Penso che Bob Martin abbia detto meglio, TDD è quello di programmare quale Double Entry è in Contabilità. Previene una certa classe di errori. Non impedisce tutti i problemi, ma fa in modo che se il tuo programma intendesse aggiungere due più due, non li ha sottratti. Il comportamento di base è importante e quando va male, puoi passare molto tempo a conoscere il tuo debugger.

+0

Hmm ... costringervi a scrivere codice "appena sufficiente" è in realtà un effetto anche della composibilità forzata. Comprendere cose come la trasparenza referenziale e gli effetti collaterali costringerà il tuo codice a fare "appena abbastanza" altrettanto bene. Il rifrattore è ciò a cui mi riferisco nel secondo punto, che rende il codice più componibile. Il software componibile è per definizione facile da rifrattore. Nella maggior parte dei casi, con determinate regole in mente, posso derivare i modelli OOP dallo stile funzionale che produce codice modulare che tende ad apparire e sentire molto simile al codice TDD. –

+0

@Rei, se la tua tesi è che è teoricamente possibile ottenere codice TDD simile senza TDD, nessuno discute con te (anche i sostenitori di TDD). Tuttavia, ciò non lo rende probabile o facile. – Yishai

+2

Per quanto riguarda il refactoring, non importa quanto sia componibile la creazione del software, se si desidera ridefinire la struttura interna del codice, si avrà paura di farlo senza una rete di sicurezza. A meno che tu non sia insolitamente buono o insolitamente sciocco. – Yishai

2

TDD non è una metodologia, è una mentalità.

TDD per ridurre i bug: Mentre la base di codice inizia a crescere, è molto importante eseguire tutti i test su ogni controllo sul controllo del codice sorgente. Il vantaggio di questo diventa evidente quando si ha un nuovo membro nel team.

TDD come paradigma di progettazione: I test sono i primi utenti del codice. Inizialmente, è molto difficile guidare il progetto usando i test. Ma, una volta che ti senti a tuo agio, ti renderai conto che il codice di prova ti aiuta effettivamente a decidere sul tuo progetto. Ciò viene naturalmente con qualche esperienza TDD. Ad esempio, con TDD ti piacerebbe racchiudere l'accesso al tuo servizio in un'interfaccia. Questo ti permette di prendere in giro. Ma la cosa più importante qui è che è il modo corretto di progettare.

TDD come documentazione La documentazione è per la documentazione del codice che deve essere utilizzata dagli sviluppatori del codice. Gli sviluppatori trovano facile leggere test unitari ben scritti, piuttosto che pagine e pagine di documentazione.

1

In Javascript o in qualsiasi linguaggio che deve essere eseguito in più ambienti bizzarri come i browser, i test di unità sono un ottimo modo per comunicare allo dove Internet Effing Explorer ha modificato la risoluzione di.

Almeno è meglio battere F5 e usare console.log() o anche avvisi.

Ma poi di nuovo, credo che questo dovrebbe essere usato per lo più per il middleware o RIA complessa - in quanto è quasi impossibile TDD interfacce utente con la logica di business poco.

Se scrivi il prossimo jQuery, i test di unità saranno tuoi amici! :)

Oh, e non dimentichiamo i grandi strumenti per js come JSTestDriver!

+0

Vero, e questo è un caso piuttosto estremo per quando i test unitari sarebbero utili: quando la piattaforma stessa cambia e devi assicurarti che il tuo codice si comporti in modo coerente in tutti loro. In quel caso non hai davvero altra scelta che testare tutto con dolorosa meticolosità. In generale, comprendo gli incentivi per i test unitari più di quanto non faccia per TDD. TDD è ancora davvero incerto per me. –

Problemi correlati