Lo sviluppo guidato dai test (TDD) ha effettivamente beneficiato di un progetto del mondo reale?


36

Non sono nuovo alla programmazione. Ho programmato (seriamente) per oltre 15 anni. Ho sempre avuto dei test per il mio codice. Tuttavia, negli ultimi mesi ho imparato il design / sviluppo guidato da test (TDD) usando Ruby on Rails . Finora non ne vedo il beneficio.

Vedo alcuni benefici nello scrivere test per alcune cose, ma pochissimi. E mentre mi piace l'idea di scrivere prima il test, trovo che dedico sostanzialmente più tempo a provare a eseguire il debug dei miei test per convincerli a dire cosa intendo realmente di quanto faccia il debug del codice reale. Ciò è probabilmente dovuto al fatto che il codice di prova è spesso sostanzialmente più complicato del codice che verifica. Spero che sia solo inesperienza con gli strumenti disponibili ( RSpec in questo caso).

Devo dire che, a questo punto, il livello di frustrazione mescolato alla deludente mancanza di prestazioni è al di là di inaccettabile. Finora, l'unico valore che sto vedendo da TDD è una libreria crescente di file RSpec che fungono da modelli per altri progetti / file. Che non è molto più utile, forse meno utile, dei file di codice del progetto reale.

Nel leggere la letteratura disponibile, noto che TDD sembra essere un enorme dispendio di tempo, ma alla fine paga. Mi sto solo chiedendo, ci sono esempi nel mondo reale? Questa enorme frustrazione ripaga mai nel mondo reale?

Spero davvero di non aver perso questa domanda da qualche altra parte qui. Ho cercato, ma tutte le domande / risposte hanno diversi anni a questo punto. È stata un'occasione rara quando ho trovato uno sviluppatore che avrebbe detto qualcosa di negativo sul TDD, motivo per cui ho trascorso tanto tempo su questo quanto ho fatto. Tuttavia, ho notato che nessuno sembra indicare esempi specifici del mondo reale. Ho letto una risposta che diceva che il ragazzo che eseguiva il debug del codice nel 2011 ti avrebbe ringraziato per avere una suite completa di test di unità (penso che quel commento sia stato fatto nel 2008).

Quindi, mi chiedo solo, dopo tutti questi anni, abbiamo finalmente degli esempi che dimostrano che il payoff è reale? Qualcuno ha effettivamente ereditato o è tornato al codice che è stato progettato / sviluppato con TDD e ha un set completo di test unitari e ha effettivamente percepito un profitto? O hai scoperto che stavi impiegando così tanto tempo a cercare di capire cosa stava testando il test (e perché era importante) che hai appena buttato via tutto il casino e scavato nel codice?


1
Mi ha risparmiato più volte: perché siamo molte persone nello stesso progetto, perché gli aggiornamenti delle gemme possono avere effetti collaterali sconosciuti, perché se tutto è verde e ho un bug, so dove non è degno trovare la radice.
celebrazione del


3
butunclebob.com/ArticleS.UncleBob.JustTenMinutesWithoutAtest Ecco una storia di Zio Bob su una situazione del mondo reale che ha affrontato.
Hakan Deryal,

1
All'inizio, ho pensato che i test sarebbero stati grandiosi per sapere dove non fossero i bug, ma ho imparato rapidamente, come ha sottolineato @Hakan nell'articolo di zio Bob, in genere viene fuori perché hai perso un caso di test. Il che rende quei test abbastanza inutili. In effetti, quell'articolo sottolinea che lo sviluppo incrementale è ciò che funziona.
James,

1
"Trovo che trascorro sostanzialmente più tempo a provare a eseguire il debug dei miei test per convincerli a dire cosa intendo realmente di quanto faccia il debug del codice reale" : ma non è proprio questo il vantaggio? Successivamente, ti accorgi ancora di dedicare molto tempo al debug del "codice effettivo"? I sostenitori di TDD sostengono che il tempo speso per trovare un modo per rendere testabile il tuo codice è in realtà uno sforzo di progettazione che andrà a beneficio del tuo codice.
Andres F.

Risposte:


26

Questo documento dimostra che TDD aggiunge un tempo di sviluppo del 15-35% in cambio di una riduzione del 40-90% della densità di difetto su progetti altrimenti uguali.

L'articolo fa riferimento al documento completo (pdf) - Nachiappan Nagappan, E. Michael Maximilien, Thirumalesh Bhat e Laurie Williams. "Realizzare il miglioramento della qualità attraverso lo sviluppo test-driven: risultati ed esperienze di quattro team industriali". ESE 2008 .

AstrattoLo sviluppo guidato dai test (TDD) è una pratica di sviluppo software che è stata utilizzata sporadicamente per decenni. Con questa pratica, un ingegnere del software passa da un minuto all'altro tra la scrittura di test unitari falliti e la scrittura di codice di implementazione per superare quei test. Lo sviluppo di Testdriven è recentemente emerso come pratica abilitante fondamentale per metodologie di sviluppo software agili. Tuttavia, poche prove empiriche supportano o confutano l'utilità di questa pratica in un contesto industriale. Sono stati condotti casi di studio con tre team di sviluppo di Microsoft e uno di IBM che hanno adottato TDD. I risultati dei casi studio indicano che la densità del difetto di pre-rilascio dei quattro prodotti è diminuita tra il 40% e il 90% rispetto a progetti simili che non hanno utilizzato la pratica TDD. Soggettivamente,

L'articolo completo sintetizza inoltre brevemente gli studi empirici rilevanti sul TDD e i loro risultati di alto livello (sezione 3 Lavori correlati ), tra cui George e Williams 2003, Müller e Hagner (2002), Erdogmus et al. (2005), Müller e Tichy (2001), Janzen e Seiedian (2006).


2
Per una discussione su Meta.StackOverflow , potresti aggiungere ulteriori informazioni dal documento che potrebbero essere rilevanti per il richiedente e per le persone future che trovano questa domanda?
Thomas Owens

2
@ThomasOwens, ho pensato che la conclusione ("TDD aggiunge un tempo di sviluppo del 15-35% in cambio di una riduzione del 40-90% nella densità dei difetti") è stata l'informazione aggiuntiva che risponde alla domanda originale <_ <

4
Questo post è stato contrassegnato per non contenere informazioni sufficienti. Non ho ancora letto il documento, ma sembra che la gente voglia aggiungere più informazioni al corpo della risposta. Forse discutere di più sulle condizioni specifiche utilizzate nello studio?
Thomas Owens

Il 99% di tutte le statistiche è fittizio. : P Ma in realtà riguarda il contesto. In che tipo di squadra? Un grande stormo di sviluppatori Java mediocri? Sì, credo che TDD li aiuterebbe con la produttività. Ma ciò non significa che avere le capacità architettoniche per progettare e valorizzare il codice robusto in primo luogo non li aiuterebbe ancora di più e IMO, il TDD test-first potrebbe facilmente impedire loro di imparare a farlo correttamente. E sì, ho sentito che aiuta con il design. In una certa misura, è probabilmente vero, ma è ancora incapace di riconoscere e un aiuto di banda per il problema di root IMO.
Erik Reppen,

sarebbe bello se alcuni altri articoli fossero elencati dalla Biblioteca digitale ACM o fossero aggiunte le parole chiave da utilizzare per il motore di ricerca. abbiamo bisogno di più rigore nelle nostre risposte quando parliamo di agile e TDD
Rudolf Olah,

16

Vedo alcuni benefici nello scrivere test per alcune cose, ma pochissimi. E mentre mi piace l'idea di scrivere prima il test, trovo che dedico sostanzialmente più tempo a provare a eseguire il debug dei miei test per convincerli a dire cosa intendo realmente di quanto faccia il debug del codice reale.

Ho lavorato a TDD negli ultimi tre anni e la mia esperienza è esattamente l'opposto. Dedico meno tempo a scrivere unit test che avrei fatto il debug del codice, se non avessi scritto i unit test.

Non solo faccio TDD, lavoro fuori-dentro, cioè prima implemento il TDD layer top / gui. L'implementazione del livello superiore definisce i requisiti per il livello successivo nel sistema, che sviluppo usando TDD, ecc. Fino a quando non sarà stato implementato tutto il codice richiesto per la funzione. Spesso, ho esperienza che dopo aver implementato una funzionalità come questa, e fumo test la funzionalità nel sistema reale, funziona la prima volta. Non sempre, ma spesso.

E dato che impiegare molto più tempo a fumare test di una funzione nel sistema reale di quanto non ci voglia per eseguire un paio di test unitari, risparmio enormi quantità di tempo. In realtà è più veloce per me implementare una funzione usando TDD che non implementare la funzione non scrivere affatto test unitari.

Ma scrivere unit test è un'abilità che deve essere appresa e padroneggiata, proprio come qualsiasi altra abilità di programmazione. Quando ho iniziato a fare TDD, avevo 12 anni di esperienza professionale con la programmazione ed ero un programmatore molto abile. Ho pensato che scrivere grandi suite di test per il codice di sistema sarebbe stata una cosa semplice. Ma con l'aumentare della quantità di codice di test e le diverse parti del sistema cambiate e i test esistenti dovevano essere modificati, ho imparato che strutturare e scrivere unit test è di per sé un'abilità che deve essere appresa e padroneggiata. Inoltre, non tutto il codice è ugualmente testabile. Il codice di sistema deve essere accoppiato molto liberamente per poter essere testato in modo efficiente. In realtà l'apprendimento del TDD mi ha aiutato a rendere il codice di sistema più liberamente accoppiato.

Ma la mia attuale efficienza nel lavoro su TDD deriva da una combinazione sia di padronanza di come scrivere test unitari, sia di padronanza della tecnologia in cui è implementato il sistema (in questo caso C #).

Fare TDD mentre apprendo una nuova tecnologia può essere difficile, ad esempio anche se ho fatto un po 'di programmazione per iPhone, non sto scrivendo una quantità significativa di test unitari, perché non padroneggio la lingua, l'obiettivo c, né lo faccio la Biblioteca. Quindi non ho idea di come strutturare i test delle mie unità, tanto meno come strutturare il codice di sistema come renderlo testabile.

Ma come funziona su progetti reali?

Sul progetto su cui ho lavorato negli ultimi due anni, anche se c'è un requisito che il codice debba essere sufficientemente coperto dai test unitari, sono l'unico del team a scrivere i primi test. Ma la grande suite di test mi dà la sicurezza di essere in grado di refactoring del sistema e credo che il sistema funzionerà correttamente se la suite di test passa.

Ma sfortunatamente, poiché molti dei test sono scritti dopo il codice di sistema, alcuni dei test stessi sono difettosi, vale a dire che non verificano realmente ciò che avrebbero dovuto testare. Questo imho non può essere evitato. Ogni volta che scrivi un pezzo di codice, c'è una probabilità che il codice non funzioni come previsto, cioè c'è un bug. Lo stesso vale per il codice di prova. Pertanto è probabile che si scriva un test che passa anche se il codice che dovrebbe testare non funziona come previsto.

Scrivendo prima il test, verificando non solo che si ottenga un errore del test, ma che il test fallisca esattamente con il messaggio di errore che ci si aspetta prima di implementare il codice di sistema riduce seriamente il rischio di un errore nel codice di test dell'unità.

Quindi, per riassumere, nella mia esperienza, una volta padroneggiata l'arte del TDD, non solo risparmierai tempo a lungo termine, ma risparmierai tempo in anticipo. Ma ci vuole tempo, anche per un programmatore esperto, per padroneggiare l'arte del TDD. E ci vuole ancora più tempo per un team di sviluppatori di diverse abilità per padroneggiare l'arte del TDD.


9

Abbiamo beneficiato enormemente.

Siamo un commerciante di livello 1, il che significa che elaboriamo oltre sei milioni di transazioni di pagamento all'anno.

Il nostro sistema di gateway di pagamento ha migliaia di test unitari e di integrazione. Questi test ci danno fiducia nella nostra capacità di elaborare i pagamenti. Vuoi essere sicuro che i freni dell'auto funzionino, vero? Vogliamo essere sicuri di non perdere la nostra attività perché non possiamo elaborare i pagamenti.

La copertura del codice ti dà quella sicurezza. Ovviamente non è abbastanza da solo, ma è un ottimo inizio.

Gran parte del nostro sistema di gateway di pagamento è stato scritto utilizzando TDD. Alcuni aspetti erano piuttosto difficili da testare, quindi abbiamo deciso di tagliare gli angoli sacrificando un po 'di copertura del codice. Torneremo indietro e affronteremo questi problemi alla fine.

Personalmente, trovo difficile scrivere qualsiasi logica prima di scrivere i test. Detto questo, mi ci è voluto un po 'di tempo per iniziare a pensare in modo TDD.

Riferimento Visa PCI: http://usa.visa.com/merchants/risk_management/cisp_merchants.html


3
"Alla fine torneremo e affronteremo questi problemi." - probabilmente no ... a meno che non ti schiaffeggino con qualche insetto orrendo. Queste aree diventeranno la spina dorsale di tutto il resto e guideranno tutti i progetti ad andare avanti perché nessuno vorrà investire le risorse per rifarli e nessuno vorrà forzare alcun cambiamento che potrebbe fare qualcosa di male. Succede ogni volta: P
Edward Strange,

Stai indovinando, quando ti sto dicendo cosa sta succedendo all'interno dell'azienda. Quando eseguiamo il commit, possiamo eseguire il commit del codice con una copertura del codice del 70%. Questo viene costantemente aumentato dal piombo CI. Entro pochi mesi, la soglia minima di copertura del codice sarà aumentata di una piccola percentuale. Dopodiché non ci sarà altra scelta che introdurre altri test.
CodeART,

7

Sebbene i test possano essere spesso considerati solo un modo di fare troppo da alcune persone, penso che valga davvero la pena in alcuni casi.

Sto sviluppando un risolutore di Sudoku Killer per la scuola da circa 3 mesi, usa molte "strategie" per rimuovere possibilità e soluzioni. Il fatto è che un errore in una possibilità può essere fatale e provocare un problema per risolvere il sudoku perché quando viene rimossa qualche possibilità, non la provi più e se fosse la soluzione, il programma non può risolvere la griglia più.

Ma è davvero difficile testare manualmente, intendo dire che esiste una griglia, posso vedere quali stratificazioni stanno facendo cosa nell'esempio del mondo reale, ma non riesco a controllare tutte le volte che si applica una strategia perché rappresentano troppi dati.

E le strategie applicate su una determinata griglia sono piuttosto "casuali", vale a dire che non userete tutto su una griglia particolare.

Quindi ho scritto test su ogni strategia, controllando il risultato su ogni cella, usando solo semplici situazioni (ad esempio solo due celle hanno già rimosso le possibilità) e mi ha risparmiato ore al giorno quando purtroppo avevo una griglia che non poteva essere risolta. Perché sapevo già dov'era il problema.


2
Sento che questa domanda sta spuntando di più durante il test, implementando successivamente la strategia. I test sono ovviamente utili per le applicazioni di debug in cui sarebbe noioso testare ogni possibilità da soli.
Alex Hope O'Connor,

6

Il vantaggio di TDD è che capisci come chiamare il tuo codice prima di scrivere il codice reale.

In altre parole, TDD aiuta a progettare la tua API.

Nella mia esperienza, ciò si traduce in API migliori che a loro volta forniscono codice migliore.


EDIT: Come ho scritto, questo era "nella mia esperienza", vale a dire quando scrivevo "progetti del mondo reale", ma sfortunatamente questo è con una base di codice sorgente chiusa che non posso far vedere al mondo. Dai commenti posso capire che questo è ciò che viene effettivamente richiesto e non solo una conferma della mera esistenza di tali progetti.

Ho anche scoperto - ancora una volta nella mia esperienza personale - che il vero vantaggio mostra quando si entra nella modalità di manutenzione perché i requisiti tendono a cambiare. Le API più pulite hanno reso molto più semplice esprimere i requisiti nuovi o modificati nel codice di test e tutti i test rendono molto facile vedere per un futuro manutentore come chiamare il codice e cosa ci si può aspettare.

I casi di test eseguono versioni della specifica e ti permettono di vedere molto, molto facilmente come invocare la tua API. Questa è forse la forma più utile di documentazione "HOW" che ho visto finora (confronta con la documentazione "WHY" come JavaDoc) poiché sei sicuro che sia corretto (altrimenti il ​​test fallirebbe).

Ultimamente, ho dovuto mantenere un client ftp con script con un set molto ampio di opzioni che influenzano il modo in cui l'applicazione funziona. TDD è stato recentemente introdotto per nuove funzionalità e l'ampia suite di test ci consente di eseguire aggiornamenti rapidi pur essendo sicuri che la funzionalità utilizzata funzioni ancora come previsto. In altre parole, questa transizione si è rivelata molto utile.


8
Questa risposta sembra essere interamente accanto alla domanda, poiché la domanda richiede esempi del mondo reale . Ma poiché tre persone hanno pensato "questa risposta è utile", mi devo perdere qualcosa.

3
D'accordo, ma non ho la reputazione di votare male. Questo è solo il "TDD che dà risultati migliori" senza alcun esempio di un progetto derivato da TDD in manutenzione per sostenere la risposta che volevo evitare.
James,

Ora che diverse persone sono d'accordo con me, oso ridimensionare. Qualche promotore, o l'autore, potrebbe fare un passo avanti e dirci perché questa è una buona risposta?

@delnan "I coraggio del downvote" - un'interessante scelta di parole. La modifica è caduta nei tuoi gusti?

Sì, ho rimosso il mio voto negativo ora che l'ho notato.

5

Quanto sia prezioso un particolare approccio ai test dipende da quanto sia critico il sistema in fase di sviluppo e da quanto dipenda da qualche altro sistema mission-critical. Un semplice script del libro degli ospiti per il tuo sito Web potrebbe difficilmente essere considerato mission-critical, ma se il sito Web su cui viene eseguito potrebbe essere potenzialmente compromesso da un bug che consentiva un input non filtrato al database e che quel sito offre un servizio vitale, allora improvvisamente diventa molto di più importante per lo script del libro degli ospiti da testare accuratamente. Lo stesso vale anche per il codice framework / libreria. Se si sviluppa un framework con un bug, anche ogni applicazione che utilizza quella funzionalità del framework ha lo stesso bug.

Lo sviluppo guidato dai test offre un ulteriore livello di sicurezza quando si tratta di test. Se si scrivono i test a fianco o anche dopo il codice che si desidera testare, c'è il rischio reale di sbagliare i test. Se scrivi prima tutti i test, il modo in cui il codice funziona internamente non può influenzare ciò per cui scrivi i test, e quindi c'è meno possibilità che tu scriva inavvertitamente test che ritengono che un determinato output errato sia corretto.

Lo sviluppo guidato dai test incoraggia anche i tuoi sviluppatori a scrivere codice facile da testare, perché non vogliono dedicarsi ancora più lavoro da fare! Il codice facile da testare tende ad essere codice facile da capire, riutilizzare e mantenere.

E la manutenzione è dove otterrai davvero i frutti di TDD. La stragrande maggioranza degli sforzi di programmazione spesi per il software è legata alla manutenzione. Ciò significa apportare modifiche al codice live per dargli nuove funzionalità, correggere bug o adattarlo a nuove situazioni. Quando si apportano tali modifiche, si desidera essere certi che le modifiche apportate abbiano l'effetto desiderato e, cosa più importante, non hanno effetti knock-in imprevisti. Se disponi di una suite di test completa per il tuo codice, è facile verificare che eventuali modifiche apportate non rompano qualcos'altro e se le modifiche apportate interrompono qualcos'altro, puoi individuare rapidamente il motivo. I benefici sono a lungo termine.

Hai detto quanto segue nella tua domanda:

Vedo alcuni benefici nello scrivere test per alcune cose, ma pochissimi. E mentre mi piace l'idea di scrivere prima il test, trovo che dedico sostanzialmente più tempo a provare a eseguire il debug dei miei test per convincerli a dire cosa intendo realmente di quanto faccia il debug del codice reale. Ciò è probabilmente dovuto al fatto che il codice di prova è spesso sostanzialmente più complicato del codice che verifica. Spero che sia solo inesperienza con gli strumenti disponibili (rspec in questo caso).

Questo sembra suggerirmi che non stai ancora facendo i test. Un test unitario dovrebbe essere estremamente semplice, solo una sequenza di chiamate di metodo, seguita da un'asserzione per confrontare il risultato atteso con il risultato effettivo. Sono pensati per essere semplici perché i bug nei test sarebbero disastrosi e se si introducono loop, branching o altri controlli di lancio del programma nel test, diventa più probabile che al test venga introdotto un bug. Se stai impiegando molto tempo a eseguire il debug dei test, significa che i tuoi test sono eccessivamente complicati e dovresti semplificarli.

Se i test non possono essere semplificati, questo fatto da solo suggerisce che c'è qualcosa di sbagliato nel codice in prova. Ad esempio, se la tua classe ha metodi lunghi, metodi con molte istruzioni if ​​/ elseif / else o switch o un numero elevato di metodi che hanno interazioni complesse dettate dallo stato corrente della classe, i test dovranno necessariamente essere estremamente complessi per fornire una copertura completa del codice e testare tutte le eventualità. Se la tua classe ha dipendenze hard coded da altre classi, questo aumenterà di nuovo il numero di cerchi che dovrai saltare per testare efficacemente il tuo codice.

Se mantieni le tue classi piccole e altamente focalizzate, con metodi brevi con pochi percorsi di esecuzione e cerchi di eliminare lo stato interno, i test possono essere semplificati. E questo è una specie del nocciolo della questione. Un buon codice è intrinsecamente facile da testare. Se il codice non è facile da testare, probabilmente c'è qualcosa che non va.

Scrivere unit test è qualcosa che ti giova a lungo termine, ed evitarli è semplicemente archiviare i problemi per dopo. Potresti non avere familiarità con il concetto di debito tecnico, ma funziona in modo molto simile al debito finanziario. Non scrivere test, non commentare codice, scrivere in dipendenze codificate e così via sono modi per indebitarsi. "Prendi in prestito" del tempo tagliando le curve all'inizio e questo potrebbe aiutarti a rispettare una scadenza serrata, ma il tempo che risparmi in precedenza nel progetto è in prestito. Ogni giorno che passa senza ripulire il codice, commentarlo correttamente o costruire una suite di test ti costerà interesse. Più dura e più aumenta l'interesse. Alla fine, scoprirai che il tuo codice è diventato un pasticcio aggrovigliato a cui non puoi apportare modifiche senza innescare conseguenze indesiderate.

Si potrebbe pensare di scrivere in anticipo i test unitari e di tenerli aggiornati come una forma di "credito tecnico". Stai mettendo del tempo in banca spendendolo presto nel progetto seguendo le buone pratiche. Guadagnerai interesse su questa previsione in seguito quando arriverai alla fase di manutenzione del progetto. Quando vuoi apportare una modifica, puoi facilmente convalidare la correttezza della modifica e che non ha effetti collaterali indesiderati e puoi ottenere aggiornamenti dalla porta rapidamente e senza complicazioni. Se vengono rilevati dei bug, è possibile aggiungere un nuovo test unit che esercita il bug, quindi correggere il bug nel codice. Alla successiva esecuzione del test unitario sarai in grado di verificare che il bug sia stato corretto e che non causasse altri problemi. Inoltre, eviterete "regressioni",

TL: DR - Sì, sono un aiuto nel mondo reale, ma sono un investimento. I benefici diventano evidenti solo in seguito.


1
Ho aderito a questa logica mesi fa. Adoro l'idea alla base di TDD, sto solo trovando la realtà un po 'sconcertante. Inoltre, noto che anche qui non ci sono esempi reali in cui l'eredità di un progetto basato su TDD ha dato i suoi frutti. Sei davvero tornato a una vecchia base di codice che aveva un sacco di test unitari e ha dato i suoi frutti.
James,

Purtroppo no, perché nessun altro sembra costruire unit test, almeno non su nessuno dei codici che ho ereditato dagli sviluppatori precedenti. La mia vita sarebbe stata molto più semplice se l'avessero fatto. Ti suggerirei di dare un'occhiata al libro nel link, che ha esempi del mondo reale, anche se è per PHP piuttosto che Rails. amazon.com/…
GordonM,

Sono un grande critico di uso generale, ma non avrei criticato nessuno per aver usato questo approccio in un sistema finanziario incorporato o critico.
Erik Reppen,

4

Sto usando TDD abbastanza spesso al lavoro. La mia esperienza è che TDD si giustifica perché non si paga tempo o sforzi aggiuntivi, lo si salva .

  • Da quando utilizzo TDD, dedico molto meno tempo al debug o altro. Funziona solo dall'inizio perché non considero il codice produttivo scritto finché i test non passano.

  • Il QA riporta molti meno bug, quindi risparmiamo sui costi di riparazione del nostro codice dopo un rilascio. Questo perché TDD non ti consente di scrivere codice senza un test, quindi la copertura del codice è molto migliore.

  • Posso eseguire il mio codice (produttivo) molto più spesso e più rapidamente perché non ho bisogno di avviare l'intero server delle applicazioni. L'avvio dell'unità di test è un ordine di grandezza più veloce. Ovviamente ne traggo beneficio solo quando il test è già eseguibile quando voglio provare il codice produttivo. Quando i test vengono dopo questo vantaggio viene perso.

  • Faccio molto meno test manuali. I miei colleghi che non praticano TDD trascorrono molto tempo facendo clic sull'applicazione fino a quando non raggiungono il punto in cui viene eseguito il nuovo codice. Eseguo il test manualmente solo una volta, poco prima di impegnarmi nel controllo della versione.

  • Anche se uso un debugger è molto più rapido eseguire il debug dell'esecuzione di un test rispetto all'intera applicazione.

Forse pensi ai test unitari come test di regressione. Questo è uno dei loro scopi, ma capirli come uno strumento di sviluppo li rende molto più utili.


La qualità è gratis!
MathAttack,

2
La cattiva qualità è costosa!
Wolfgang,

3

Un altro vantaggio (oltre a quelli menzionati dalle altre persone che hanno risposto) entra in gioco quando i tester di accettazione del cliente o (gli utenti del cielo vietano) la produzione scoprono un bug. Trasforma il bug report in un test in stile TDD per la classe che sembra essere in errore. Guarda fallire. Aggiustalo. Guardalo passare. Allora sai che hai corretto l'errore. Questa tecnica mi ha risparmiato ore.


2

Bene, so che traggo beneficio personalmente dall'essere due volte più veloce dei miei colleghi sviluppatori e scrivere meno della metà dei bug che fanno perché NON fanno TDD. Le persone che probabilmente dovrebbero essere migliori di me anche ... Le ho sovraperformate di almeno un fattore 2.

Non ci sono arrivato subito. Sono abbastanza bravo a scrivere codice dal bracciale e senza imbracatura. Sembrava un grande spreco scrivere tutta questa merda in più. Ma fa diverse cose, tra cui (non esclusivo):

  • Costringere un design orientato al disaccoppiamento e al riutilizzo (tutto deve essere riutilizzato in un test unitario).
  • Fornire una piattaforma per sviluppare codice in piccoli blocchi e moduli in modo da non dover capire e finire tutto prima di eseguire un semplice tipo di test "Compila e accetta input".
  • Fornire una piattaforma di test rapida per apportare modifiche quando le persone richiedono modifiche alle funzionalità che non mi aspettavo.

Un esempio su questo bit successivo è un progetto a cui sto attualmente lavorando in cui il lead ha improvvisamente deciso di riscrivere TOTALMENTE il protocollo di comunicazione che ha usato per quasi 0 motivi. Sono stato in grado di rispondere a quel cambiamento in 2 ore come avevo già disaccoppiato da tutto il resto e sono stato in grado di lavorarci su in modo completamente indipendente fino all'ultimo collegamento e integrarlo test passo. La maggior parte dei miei colleghi probabilmente ci sarebbe stata per un giorno o più perché il loro codice non sarebbe stato disaccoppiato e sarebbero cambiati qui, lì, ovunque ... compilando tutto ... test di integrazione ... ripeti, ripeti ... impiega molto più tempo in questo modo e non è affatto stabile.


2

La risposta è si. Nella mia azienda sviluppiamo un'applicazione C ++ da oltre 20 anni. L'anno scorso siamo entrati in TDD in alcuni nuovi moduli e le percentuali di difetto sono diminuite in modo significativo. Ci è piaciuto così tanto che alcuni di noi stanno persino aggiungendo test al codice legacy ogni volta che cambiamo qualcosa lì.

Inoltre, un intero modulo è stato completato dall'inizio alla fine, passando attraverso la produzione, senza mai dimostrare un bug (ed è anche un modulo critico). Il suo sviluppo è stato quindi più veloce del solito, perché di solito ciò che accadrebbe altrimenti è che un modulo sarebbe "completato", solo per tornare 4-5 volte dal beta test per la correzione di bug. È stato un miglioramento sostanziale e anche gli sviluppatori sono stati più contenti del nuovo processo.

Non ho fatto molti Rails TDD, ma ho fatto molto in C ++, C #, Java e Python. Posso dirti che sicuramente funziona. La mia ipotesi è che stai spendendo molto tempo a pensare ai nomi dei test perché non sei abbastanza sicuro. Scrivi prima il test, ma lascia fluire la tua creatività ...

Ho notato che una volta che hai veramente capito il TDD, inizi a preoccuparti un po 'meno di "Come ho intenzione di nominare questo test ... argh!", E semplicemente fluisci con esso, refactoring e adattamento già scritto test per adattarsi alla situazione attuale.

Tempo per un suggerimento

Suggerimento n. 1

Quindi il consiglio che penso dovrebbe aiutarti di più è di non preoccuparti così tanto. Una delle cose più belle di TDD è che ti dà il coraggio di cambiare cose che sono già scritte e funzionanti. E questo include i test.

Suggerimento n. 2

Inizia nuovi test di classe con un semplice test "canCreate", solo per impostare la tua mente nella giusta direzione, come in "Ok, sto lavorando su questa classe ora ... giusto."

Quindi inizia ad aggiungere altri test, ma solo uno alla volta, e assicurati che ogni test che crei, sia il prossimo caso più semplice che ti viene in mente in quel momento (pensaci per non più di 30 secondi, quindi timeout con il meglio che hai a quel punto).

E ricorda

Non preoccuparti del refactoring dei test esistenti o della rimozione di quelli obsoleti o ridondanti. Non molte persone lo capiscono, ma in TDD in realtà ottieni 2 reti di sicurezza al prezzo di 1. I tuoi test sono una rete di sicurezza per le modifiche del codice di produzione, ma il tuo codice di produzione è anche una rete di sicurezza per il refactoring dei test. La relazione è reciproca. In realtà è un buon caso di accoppiamento stretto.

Dagli un'altra possibilità. E lasciatemi raccomandare di guardare i cast di codici puliti , specialmente quelli su TDD.


1

Esempio non banale nel mondo reale:

Ho dovuto scrivere una funzione di trasformazione della struttura dei dati. L'input sarebbe una struttura di dati (in realtà una struttura di dati nidificata, molto simile a un albero) e l'output sarebbe una struttura di dati simile. Non riuscivo a visualizzare l'attuale trasformazione nella mia mente. Uno dei principali vantaggi di TDD (per me, comunque) è l'applicazione di piccoli passi se non sai come procedere (vedi "TDD di Esempio" di Kent Becks). Poiché non sapevo dove stavo andando, ho iniziato con i semplici casi di base come input vuoti o banali e sono arrivato a casi più complicati fino a quando ho pensato di averli coperti tutti. Alla fine ho avuto un algoritmo funzionante e i test che lo hanno dimostrato. I test non solo dimostrano che la mia implementazione sta funzionando in questo momento, ma mi impediscono di rovinare qualcosa in seguito.


-1

Non mi piace l'idea di seguire ciecamente eventuali consigli generici perché non credo che ci sia un suggerimento unico per tutti che aiuterà la maggior parte degli sviluppatori a diventare più produttivi e ridurre i difetti nelle applicazioni. Dalla mia esperienza, più ti preoccupi della qualità, più perderai nella quantità di nuove funzionalità fornite. Quindi il livello di importanza che vuoi dare alla qualità rispetto alla consegnabilità dipenderà effettivamente dal tuo prodotto e dalla strategia attuale e molto probabilmente sarà qualcun altro a decidere strategicamente ciò che è più importante per il momento: robustezza o consegnabilità.

Anche questa decisione non è in bianco o nero. Molto probabilmente alcune parti della tua applicazione devono essere robuste mentre altre no. Una volta identificate le parti che dovrebbero avere un alto grado di qualità, è necessario concentrarsi su di esse dal punto di vista del collaudo poiché si desidera garantire un'alta qualità a tali parti.

Tutto ciò che ho detto finora non ha nulla a che fare con TDD specificamente nel senso di scrivere test prima dell'implementazione, ma credo sia importante separare i vantaggi di avere testato il codice rispetto a scrivere prima i test.

Una volta compresi i vantaggi del test stesso, TDD o meno, è quindi possibile discutere la strategia di test per il codice che si desidera venga coperto dai test. Alcune persone sostengono che se in seguito scriverai i test ti mancheranno alcune condizioni, ma credo che dovresti essere tu a valutare se questo è applicabile a te. Certamente non si applica a me.

Quindi, ecco come funziona per me. Fondamentalmente ci sono due situazioni che mi faranno scrivere test: migliorerà solo la qualità o accelererà anche il mio sviluppo di alcune funzionalità. Quindi, una situazione in cui scriverò dei test è quando non ci sono nuove funzionalità nel backlog e posso quindi decidere di migliorare le prestazioni dell'applicazione, semplificare la base di codice o migliorare la suite di test. Un'altra situazione è la necessità di disporre di un solido codice funzionante in cui i bug avrebbero un impatto abbastanza grande sui clienti reali. Ancora un altro è per testare codice complesso che è facile da decifrare quando ci si lavora. Ad esempio, c'è una classe QueryBuilder nella mia base di codice che si occupa di molti casi d'uso e sarebbe facile romperne alcuni durante la correzione di un bug o l'aggiunta di una nuova funzionalità.

Infine, c'è il caso in cui la scrittura dei test mi consente innanzitutto di scrivere una funzione più velocemente, quindi di non scrivere affatto i test. QueryBuilder è stato anche un caso in cui è stata applicata anche questa regola, ma ciò non significa che TDD sarà anche il percorso migliore. Un altro esempio di aiuto di TDD sulla velocità di sviluppo è per esempio il test della generazione di Excel, mentre nell'applicazione reale potrebbe essere necessario eseguire diversi passaggi ogni volta che si desidera verificare alcune condizioni specifiche della generazione. O se è necessario creare alcuni record per testare una funzione ed è difficile o impossibile eliminarli manualmente dopo aver testato manualmente il codice.

Quindi, se è più semplice riprodurre i passaggi per eseguire un codice di sviluppo in modo programmatico (attraverso i test), provalo. Ma se scrivere il test è più complicato di testarlo manualmente, allora devi decidere se questo è il momento di concentrarti sulla qualità o se hai molte richieste nel tuo backlog e qualcuno in azienda probabilmente lo saprà meglio e ti consentirà sapere dove dovresti concentrarti in base alle loro esigenze attuali e alla strategia aziendale.

In un mondo ideale tutto il codice viene testato, ma non si può pretendere che non ci sia un compromesso e supporre che TDD sia sempre il percorso migliore e unico. Come per tutte le migliori pratiche là fuori, devi sempre concentrarti su ciò che è meglio per l'azienda per cui lavori anziché su ciò che è meglio per te. Una volta che sei un lavoratore autonomo, sei libero di decidere di eseguire TDD tutto il tempo se pensi che sia il percorso migliore. Se la tua azienda ritiene che tutto il codice debba essere testato, devi scrivere i test per tutto il codice che scrivi. Ma per la maggior parte dei casi devi avere una visione d'insieme e comprendere i compromessi prima di prendere qualsiasi decisione. Siamo spiacenti, ma questa non è una scienza esatta e non esiste una risposta facile (o difficile) adatta per tutti che dovresti seguire ogni volta.

Proprio come con i modelli di design. Comprendi come funzionano e perché sono stati creati e che tipo di problemi risolvono e quali sono anche i loro svantaggi. Comprendere il ragionamento è molto più importante del ricordare le soluzioni proposte. Ciò che oggi è un'operazione costosa può essere facilmente raggiunto domani con altre tecnologie. Se la premessa per una soluzione ben consolidata non è più valida molto probabilmente la soluzione non è più la migliore da usare. Quando i requisiti, la tecnologia disponibile o la strategia aziendale sono cambiati, dovresti sempre rivalutare la tua cassetta degli attrezzi e quando ciò accade, devi capire perché hai scelto ogni percorso in primo luogo invece di prenderli in borsa come le migliori opzioni.


questo non tenta nemmeno di rispondere alla domanda posta: "abbiamo finalmente degli esempi che dimostrano che il payoff è reale? Qualcuno ha effettivamente ereditato o è tornato al codice che è stato progettato / sviluppato con TDD e ha un set completo di unit test e hai davvero sentito un profitto? "
moscerino del

1
Risponde, ma poiché non condividi la mia opinione, dai -1 ad essa :) Praticamente chiunque non proverà a mostrare i valori di TDD darà una risposta indesiderata dal tuo punto di vista;) Fammi indovinare . Sei un evangelizzatore di TDD, vero? :) A proposito, la vera domanda dell'autore è se TDD paga o no. Non è necessario esercitarsi con TDD per rispondere. Fortran paga per la scrittura di app Web? Hai provato prima di rispondere?
rosenfeld,

Non ho un'opinione su TDD e non uso i voti come Mi piace / Non mi piace (è un sito di domande e risposte, non un Facebook). Secondo la mia lettura, questa "risposta" semplicemente non affronta affatto la domanda posta, né positivamente né negativamente
moscerino del

Dal mio punto di vista, questa non è una domanda tecnica, come "come posso fare X con nginx?". Esistono risposte giuste a domande del genere, ma non a domande qualitative e soggettive come questa, quando l'autore vuole effettivamente conoscere le opinioni degli altri sul TDD e se ne valga la pena. Quello era il mio tentativo di mostrare il mio punto di vista. Non ho idea di come una risposta potrebbe essere quella giusta in quanto tutte mi sembrano opinioni personali. Non è possibile misurare efficacemente se TDD vale o no. Qualsiasi articolo che tenta di farlo è fondamentalmente sbagliato.
rosenfeld,

"Questo sito è tutto il tour che ottiene risposte . Non è un forum di discussione ..."
moscerino del
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.