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.