Perché TDD funziona? [chiuso]


92

Lo sviluppo guidato dai test (TDD) è grande in questi giorni. Lo vedo spesso come una soluzione per una vasta gamma di problemi qui in Programmers SE e in altri luoghi. Mi chiedo perché funzioni.

Da un punto di vista ingegneristico, mi confonde per due motivi:

  1. L'approccio "write test + refactor till pass" sembra incredibilmente anti-ingegneria. Se gli ingegneri civili usassero questo approccio per la costruzione di ponti o i progettisti di automobili per le loro auto, ad esempio, rimodellerebbero i ponti o le auto a costi molto elevati e il risultato sarebbe un disastro riparato senza un'architettura ben congegnata . La linea guida "refactor till pass" è spesso presa come mandato per dimenticare la progettazione architettonica e fare tutto il necessario per conformarsi al test; in altre parole, il test, anziché l'utente, stabilisce il requisito. In questa situazione, come possiamo garantire buone "ilicità" nei risultati, ovvero un risultato finale che non è solo corretto ma anche estensibile, robusto, facile da usare, affidabile, sicuro, sicuro, ecc.? Questo è ciò che fa di solito l'architettura.
  2. I test non possono garantire il funzionamento di un sistema; può solo dimostrare di no. In altre parole, il test può mostrare che un sistema contiene difetti se non supera un test, ma un sistema che supera tutti i test non è più sicuro di un sistema che non li supera. La copertura del test, la qualità del test e altri fattori sono cruciali qui. Le false sensazioni sicure che un esito "tutto verde" produce a molte persone sono state segnalate nelle industrie civili e aerospaziali come estremamente pericolose, perché possono essere interpretate come "il sistema va bene", quando in realtà significa "il sistema è buono come nostra strategia di test ". Spesso, la strategia di test non viene controllata. Oppure, chi verifica i test?

In sintesi, sono più preoccupato per il bit "guidato" in TDD che per il bit "test". Il test è perfettamente OK; quello che non capisco è guidare il design facendolo.

Vorrei vedere le risposte contenenti le ragioni per cui TDD in ingegneria del software è una buona pratica e perché i problemi che ho spiegato sopra non sono rilevanti (o non abbastanza rilevanti) nel caso del software. Grazie.


53
Ponti, automobili e altri progetti fisici non sono per nulla malleabili come i software. Questa è una distinzione importante e significa che i confronti tra software e ingegneria reale non sono sempre rilevanti. Ciò che funziona per i bridge potrebbe non funzionare per il software e viceversa.
Lars Wirzenius,

9
Sono in qualche modo d'accordo con i tuoi dubbi. Ad esempio, confesso di avere l'impressione che avere una suite di test possa avere come effetto collaterale un'attenzione in qualche modo "attenuata" quando si scrive un codice. Naturalmente i test sono una buona cosa (obbligatorio se si desidera avere la possibilità di refactoring), ma solo se integrano l'attenzione ai dettagli, i casi di frontiera, l'efficienza o l'estensibilità e non se lo sostituiscono.
6502

2
@ 6502: Certamente! TDD non è un proiettile d'argento e non risolverà tutti i problemi che sorgono durante lo sviluppo del software. È tuttavia un metodo utile per organizzare il flusso di lavoro. Ad esempio, è possibile imporre un requisito per cui tutti i casi di frontiera sono coperti da test. Devi ancora sapere quali sono questi casi limite, ma ora hai anche uno strumento per verificare se il tuo codice li gestisce correttamente.
Mchl

2
@CesarGon, potresti anche essere interessante in questa domanda che ho posto su SO qualche tempo fa ... Non proprio TDD, ma correlato ... Alcune risposte molto illuminanti lì.
AviD

6
Che meraviglia che un analogo di ingegneria civile / sviluppo software non regge. Allo stesso modo, ho notato spesso che non riesco a cucinare i pancake nello stesso modo in cui taglio il prato.

Risposte:


66

Penso che ci sia un malinteso qui. Nella progettazione del software, il design è molto vicino al prodotto. Nell'ingegneria civile, nell'architettura, il design è disaccoppiato dal prodotto reale: ci sono progetti che ne sostengono il design, che vengono poi materializzati nel prodotto finito e che sono separati da enormi quantità di tempo e fatica.

TDD sta testando il progetto. Ma ogni progetto di auto e design di edifici viene testato. Le tecniche di costruzione vengono prima calcolate, quindi testate su scala minore, quindi testate su scala più ampia, prima di essere utilizzate in un edificio reale. Quando hanno inventato le travi ad H e il carico, ad esempio, state certi che questo è stato provato e riprovato prima che costruissero effettivamente il primo ponte con esso.

Anche i progetti di auto vengono testati, progettando prototipi, e sì, certamente regolando cose che non sono esattamente giuste, fino a quando non all'altezza delle aspettative. Parte di questo processo, tuttavia, è più lenta, perché come hai detto, non puoi fare molto casino con il prodotto. Ma ogni riprogettazione di un'auto si basa sulle esperienze apprese da quelle precedenti e ogni edificio ha alle spalle circa mille anni di fondamenti sull'importanza di spazio, luce, isolamento, resistenza, ecc. I dettagli sono cambiati e migliorati, sia negli edifici e in redesign per quelli più recenti.

Inoltre, le parti vengono testate. Forse non esattamente nello stesso stile del software, ma le parti meccaniche (ruote, accenditori, cavi) sono di solito misurate e messe sotto stress per sapere che le dimensioni sono corrette, non si devono vedere anomalie, ecc. Potrebbero essere raggi x o laser- misurati, toccano i mattoni per individuare quelli rotti, potrebbero essere effettivamente testati in una configurazione o in un'altra, oppure disegnano una rappresentazione limitata di un grande gruppo per metterlo davvero alla prova.

Queste sono tutte cose che puoi mettere in atto con TDD.

E in effetti, i test non sono garantiti. I programmi si bloccano, le macchine si guastano e gli edifici iniziano a fare cose divertenti quando soffia il vento. Ma ... la "sicurezza" non è una domanda booleana. Anche quando non puoi mai includere tutto, essere in grado di coprire - diciamo - il 99% delle eventualità è meglio che coprire solo il 50%. Non testare e poi scoprire che l'acciaio non si è stabilizzato bene, è fragile e si rompe al primo colpo di martello quando hai appena installato la tua struttura principale è un semplice spreco di denaro. Il fatto che ci siano altre preoccupazioni che potrebbero ancora danneggiare l'edificio non lo rende meno stupido per consentire a un difetto facilmente prevenibile di abbattere il tuo design.

Quanto alla pratica del TDD, è una questione di bilanciamento. Il costo di farlo in un modo (ad esempio, non testare e poi raccogliere i pezzi in un secondo momento), rispetto al costo di farlo in un altro modo. È sempre un equilibrio. Ma non pensare che altri processi di progettazione non abbiano test e TDD in atto.


7
+1 per parlare di dove si verificano i test nella produzione. Ottimo punto
Adam Lear

11
Dici "le parti sono testate". Sicuro, ma non testato progettato. Una parte di aeromobile non è progettata in modo testato, ma in modo architettonico e di grande design. Le somiglianze con TDD sono inesistenti qui.
CesarGon,

3
In aggiunta a ciò: TDD, a mio avviso, riguarda principalmente i modi per assicurarsi di poter controllare le parti piuttosto che un grande "tutto o niente" alla fine. Ma l'adagio di TDD, "costruire prima un test" non vuole essere "fare un test prima di pensare a ciò che si desidera realizzare". Perché pensare a un test fa parte della progettazione. Specificare cosa si desidera fare quella parte esatta, è la progettazione. Prima di iniziare a scrivere, hai già fatto un po 'di progettazione. (In questo modo penso che il termine "progettazione guidata dai test" implichi in modo fuorviante un percorso a senso unico, in cui si tratta in realtà di un circuito di feedback).
Inca,

2
+1: il software è puramente design. L'analogia del bridge nella domanda è completamente sbagliata. TDD applica totalmente i test delle unità esterne. Il Design Test-Driven si applica a tutti gli strati del design.
S.Lott

3
@CesarGon: No, TDD sta guidando lo SVILUPPO testando. È diverso dal guidare il design. Il design determina come utilizzeresti il ​​sistema e quindi quali test dovresti implementare per replicare quel comportamento. L'implementazione di questi test spesso ti aiuta a perfezionare il design, però.
Deworde,

26

IMO, la maggior parte delle storie di successo di TDD sono false e solo per scopi di marketing. Potrebbe esserci pochissimo successo, ma solo per piccole applicazioni. Sto lavorando a una grande applicazione Silverlight in cui vengono utilizzati i principi TDD. L'applicazione ha centinaia di test ma non è ancora stabile. Diverse parti dell'applicazione non sono verificabili a causa delle complesse interazioni dell'utente. Test risultanti con molte beffe e codice difficile da capire.

Inizialmente quando abbiamo provato TDD, sembra tutto a posto. Sono stato in grado di scrivere molti test e deridere le parti che sono difficili per un test unitario. Una volta che hai una buona quantità di codice ed è richiesta una modifica dell'interfaccia, sei fregato. È necessario correggere molti test e riscrivere più test rispetto alla modifica effettiva del codice.

Peter Norvig spiega la sua opinione su TDD nel libro Coders At Work.

Seibel: E l'idea di usare i test per guidare la progettazione?

Norvig: Vedo i test più come un modo di correggere gli errori piuttosto che come un modo di progettare. Questo approccio estremo di dire: "Beh, la prima cosa che fai è scrivere un test che dice che alla fine ottengo la risposta giusta", e poi lo esegui e vedi che fallisce, e poi dici: "Cosa devo fare? bisogno del prossimo? ”- non sembra il modo giusto di progettare qualcosa per me. Sembra solo se fosse così semplice che la soluzione preordinata avrebbe senso. Penso che devi pensarci prima. Devi dire: “Quali sono i pezzi? Come posso scrivere i test per i pezzi fino a quando non so cosa sono alcuni di essi? ”E poi, una volta che lo hai fatto, allora è buona disciplina fare dei test per ciascuno di quei pezzi e capire bene come interagiscono tra loro e i casi limite e così via. Tutti dovrebbero avere dei test. Ma non credo che tu guidi l'intero progetto dicendo: "Questo test è fallito".


7
Ora, se dici questi fatti a persone e consulenti TDD, la risposta che otterrai sarebbe:well, you haven't done TDD right!
Navaneeth KN

10
E avrebbero ragione. Stiamo eseguendo BDD / TDD su un sistema a volume molto elevato e sta funzionando bene. I test sono lì per dirti che hai rotto il comportamento previsto. Se stai andando e cambiando in seguito "rompendo" i test, in realtà stai sbagliando. I test dovrebbero essere prima cambiati per consolidare il NUOVO comportamento del sistema, quindi lo cambi. E sì, se lo stai facendo bene, scrivi i tuoi test iniziando con "cosa deve fare questa cosa" e il processo di scrittura del test ti aiuta a pensare "di cosa ha bisogno l'IT per fare il suo lavoro". Oh, e nessun consulente è mai stato usato ...
Andy,

4
Fare molti test non ti esonera dalla creazione di un progetto adeguato. Un design altamente accoppiato indipendentemente da quanti test sono costruiti attorno e sarà sempre fragile. l'inclusione dei test in questo progetto può rendere il tutto ancora peggio.
Newtopian,

3
Non si tratta di sbagliare o di essere un progetto altamente accoppiato. Il fatto è che le interfacce cambiano. Ciò significa che tutti i test che utilizzano tale interfaccia devono cambiare. Sui sistemi di grandi dimensioni, mantenere i test sincronizzati con le modifiche richieste può iniziare a sopraffare l'implementazione. Questo diventa un problema ancora più grande se stai facendo uno sviluppo agile poiché le probabilità di cambiare l'interfaccia sono molto più probabili. È divertente come quando le metodologie non funzionano, i sostenitori della metodologia insistono sul fatto che stai sbagliando. È più probabile che la metodologia non sia adatta a tutti i domini problematici.
Dunk,

2
Nella mia esperienza facendo TDD funziona per piccole applicazioni o moduli. Quando devo lavorare su qualcosa di complesso, TDD mi rallenta perché mi costringe a scrivere una specifica dettagliata (eseguibile) prima di avere l'immagine generale nella mia mente: quindi mi perdo nei dettagli troppo presto, e spesso devo butto via un sacco di test se scopro che non ho bisogno di determinate classi (sto ancora giocando con il design). In questi casi, preferisco prima ottenere un progetto complessivo ragionevole, quindi perfezionare i dettagli dell'implementazione (possibilmente usando TDD).
Giorgio,

25

Test Driven Design funziona per me per i seguenti motivi:

È una forma eseguibile della specifica.

Ciò significa che puoi vedere dai casi di test:

  1. CHE il codice chiamato riempie completamente la specifica poiché i risultati previsti sono proprio lì nei casi di test. L'ispezione visiva (che prevede il superamento dei casi di test) può dire immediatamente "oh, questo test verifica che la chiamata a fattura Azienda in questa situazione, dovrebbe avere QUESTO risultato".
  2. COME deve essere chiamato il codice. Le fasi effettive necessarie per eseguire i test vengono specificate direttamente senza alcun ponteggio esterno (i database vengono derisi, ecc.).

Scrivi prima la vista dall'esterno.

Spesso il codice viene scritto in un modo in cui prima risolvi il problema e poi pensi a come chiamare il codice che hai appena scritto. Questo spesso fornisce un'interfaccia imbarazzante perché è spesso più facile "semplicemente aggiungere una bandiera" ecc. Pensando che "dobbiamo fare QUESTO in modo che i test siano simili a QUI" in avanti lo capovolgi. Ciò darà una migliore modularità, poiché il codice verrà scritto in base all'interfaccia chiamante, non viceversa.

Questo di solito si tradurrà in un codice più pulito che richiede meno documentazione esplicativa.

Hai finito più velocemente

Dal momento che hai le specifiche sul modulo eseguibile, hai finito quando passa la suite di test completa. Puoi aggiungere altri test mentre chiarisci le cose a un livello più dettagliato, ma come principio di base hai un indicatore molto chiaro e visibile dei progressi e quando hai finito.

Ciò significa che puoi sapere quando è necessario o meno il lavoro (aiuta a superare un test) alla fine devi fare di meno.

Per quelli su cui può essere utile, ti incoraggio a usare TDD per la tua prossima routine in biblioteca. Impostare lentamente una specifica eseguibile e fare in modo che il codice superi i test. Al termine, la specifica eseguibile è disponibile per tutti coloro che hanno bisogno di vedere come invocare la libreria.

Studi recenti

"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, i team hanno registrato un aumento dal 15 al 35% di tempo di sviluppo iniziale dopo l'adozione del TDD. " ~ Risultati ed esperienze di 4 squadre industriali


5
Aggiungerei a questo che in realtà hai una linea guida abbastanza ragionevole e chiara su quando hai finito. Senza una procedura chiara per verificare obiettivamente che hai completato l'attività a portata di mano, è difficile da sapere. La mia esperienza personale include molte ore e giorni sprecati a "negoziare" se un'attività è stata completata e un continuo e costante spostamento della linea. Ciò influisce su tutti i livelli della gestione del progetto, compresa la pianificazione, per come è possibile pianificare tale attività? Obiettivi più chiari con tempi di risposta più rapidi aumentano la produttività E la comunicazione.
Edward Strange,

Questa dovrebbe essere la risposta accettata.
Niing

19

Il processo di creazione del software non è il processo di scrittura del codice. Nessun progetto software dovrebbe iniziare prima senza un piano di "ampia portata". Proprio come un progetto per colmare due sponde di un fiume ha bisogno di un tale piano per primo.

L'approccio TDD riguarda (principalmente) i test unitari - almeno così le persone tendono a pensarci - che sta creando i bit di codice software di livello più basso. Quando tutte le caratteristiche e i comportamenti sono già stati definiti e sappiamo effettivamente cosa vogliamo ottenere.

Nell'ingegneria strutturale sembra un po 'così:

'Abbiamo questi due pezzi di metallo collegati insieme e la connessione deve sostenere forze di taglio nell'ordine di x. Testiamo quale metodo di connessione è il migliore per farlo '

Per verificare se il software funziona nel suo insieme, progettiamo altri tipi di test come test di usabilità, test di integrazione e test di accettazione. Anche questi dovrebbero essere definiti prima che inizi il vero lavoro di scrittura del codice e vengano eseguiti dopo che i test unitari sono verdi.

Vedi V-Model: http://en.wikipedia.org/wiki/V-Model_%28software_development%29

Vediamo come funzionerebbe per un bridge:

  1. Un governo locale dice a una società di costruzione di ponti: "Abbiamo bisogno di un ponte per collegare questi due punti. Il ponte deve essere in grado di consentire n quantità di traffico all'ora ed essere pronto per il 21 dicembre 2012 '- questa è una definizione di test di accettazione. La società non otterrà l'intero importo (o alcuno) denaro, se non può superare quel test.

  2. La direzione dell'azienda decide il programma del progetto. Hanno creato gruppi di lavoro e stabilito obiettivi per ogni squadra. Se le squadre non raggiungeranno questi obiettivi, il ponte non sarà costruito in tempo. Tuttavia, qui c'è un certo livello di flessibilità. Se uno dei team ha dei problemi, la società può compensarlo modificando i requisiti, cambiando i subappaltatori, assumendo più persone ecc. In modo che l'intero progetto soddisfi ancora l'obiettivo fissato al punto # 1.

  3. All'interno di un team responsabile della progettazione di particolari componenti del ponte sembra nell'esempio che ho fornito sopra. A volte la soluzione è ovvia, poiché disponiamo di un ampio bagaglio di conoscenze sulla costruzione di ponti (è come utilizzare una libreria ben collaudata nello sviluppo del software - si presume che funzioni come pubblicizzato). A volte è necessario creare diversi progetti e testarli per scegliere quello migliore. Tuttavia, i criteri su cui viene testato il componente sono noti in anticipo.


Se ti capisco correttamente, stai dicendo che TDD è OK fintanto che (a) è usato solo per i test unitari e (b) è accompagnato anche da altri approcci di test. In tal caso, potrebbe essere indicato il punto numero 2 nel PO. Come indirizzeresti al punto numero 1?
CesarGon,

@CesarGon: TDD funziona egregiamente anche per i test di integrazione.
sevenseacat,

Il punto 1 si riduce all'atto, che prima che il progetto finale di un'automobile o di un ponte venga accettato, passa attraverso molte reiterazioni durante le quali tutti i suoi dettagli vengono rivisti e testati rispetto ai requisiti imposti dal "piano di ampia portata". È fatto principalmente su carta (o nella memoria del computer), perché è più economico in questo caso, ma nota che spesso ci sono prototipi fisici in costruzione sia dell'intera costruzione (forse non in caso di bridge) sia dei suoi componenti.
Mchl

@Karpie: E anche per i test di accettazione! Dovresti sapere in anticipo cosa è necessario affinché il tuo lavoro venga accettato dal cliente.
Mchl

1
Va bene allora. Praticamente il primo team ad iniziare i lavori è un team di architetti a cui viene detto di progettare un ponte in grado di soddisfare i criteri dei clienti, pur essendo anche economico e possibilmente bello, senza scendere alla prima forte raffica di vento. Il team potrebbe proporre alcuni progetti approssimativi che soddisfano più o meno questi criteri, quindi selezionarne uno e lavorarci su più dettagli, ripetere, ripetere, ripetere fino a quando il progetto non è pronto (cioè soddisfa i criteri indicati ed è sufficientemente dettagliato in modo che possono iniziare altre fasi del progetto)
Mchl

18

Nella mia mente TDD funziona perché

  • Ti costringe a definire cosa vuoi che l'unità faccia prima di decidere sull'implementazione a un livello di precisione generalmente non coperto da alcuna specifica o requisito doc
  • Rende il codice intrinsecamente riutilizzabile, poiché è necessario utilizzarlo sia in test che in scenari di produzione
  • Ti incoraggia a scrivere il codice in un dispositivo più piccolo per testare blocchi che tendono a portare a progetti migliori

In particolare sui punti sollevati

  • Il codice è più malleabile rispetto al mattone o all'acciaio, quindi è più economico da modificare. È ancora più economico se si dispone di test per assicurarsi che il comportamento sia invariato
  • TDD non è una scusa per non progettare: un'architettura di alto livello è generalmente consigliata, ma non con troppi dettagli. Il design di Big Up Front è scoraggiato, ma è incoraggiato a fare abbastanza design
  • TDD non è in grado di garantire il funzionamento di un sistema, ma impedisce che passino molti piccoli errori che altrimenti verrebbero persi. Anche perché in genere incoraggia un migliore codice fattorizzato, è spesso più facile da capire, quindi meno probabilità di essere buggy

3
Dovresti anche aggiungere che una volta scoperti i difetti puoi assicurarti che non vengano ripetuti mentre aggiungi un altro test.
Andy,

16

TL; DR

La programmazione è ancora un'attività di progettazione, non di costruzione. Scrivere unit test dopo il fatto conferma solo che il codice fa quello che fa, non che fa qualcosa di utile. I fallimenti dei test sono il vero valore perché ti consentono di rilevare gli errori in anticipo.

Il codice è design

Nel capitolo 7 di PPP "Zio Bob" parla direttamente di questo problema. Molto presto nel capitolo, fa riferimento a un eccellente articolo di Jack Reeves in cui propone che il codice sia design (il link va a una pagina che raccoglie tutti e tre i suoi articoli sull'argomento).

La cosa interessante di questo argomento è che egli sottolinea, a differenza di altre discipline ingegneristiche in cui la costruzione è un'attività molto costosa, la costruzione di software è relativamente gratuita (compilazione di hit nel tuo IDE e hai il tuo software costruito). Se si considera la scrittura del codice come un'attività di progettazione anziché come attività di costruzione, il ciclo di rifattore rosso-verde è fondamentalmente un esercizio di progettazione. Il tuo design si evolve mentre scrivi i test, il codice per soddisfarli e il refactor per integrare il nuovo codice nel sistema esistente.

TDD come specifica

I test unitari che scrivi per TDD sono una traduzione diretta delle specifiche quando le capisci. Scrivendo un codice che soddisfi minimamente le tue specifiche (fa diventare verdi i tuoi test), tutto il codice che hai scritto è lì per uno scopo specifico. Se tale scopo è stato raggiunto o meno viene convalidato da un test ripetibile.

Scrivi test sulla funzionalità

Un errore comune nel test unitario si verifica quando si scrivono i test dopo il codice, si finisce per testare che il codice fa quello che fa. In altre parole, vedrai test come questo

public class PersonTest:Test
{
   [Test]
   TestNameProperty()
   {
      var person=new Person();
      person.Name="John Doe";
      Assert.AreEqual("John Doe", person.Name);
   }
}

Mentre immagino che questo codice possa essere utile (assicurati che qualcuno non abbia fatto qualcosa di osceno con una proprietà semplice). Non serve per convalidare una specifica. E come hai detto, scrivere questo tipo di test ti porta solo così lontano.

Mentre il verde è buono il valore risiede nel rosso, ho avuto il mio primo vero momento "aha" nel TDD quando ho avuto un fallimento imprevisto del test. Avevo una serie di test che avevo per un framework che stavo costruendo. Aggiungendo una nuova funzionalità, ho scritto un test per questo. Quindi ha scritto il codice per superare il test. Compilare, testare ... ha ottenuto un green sul nuovo test. Ma ho anche ottenuto un rosso su un altro test che non mi aspettavo di diventare rosso.

Guardando il fallimento, tiro un sospiro di sollievo perché dubito che avrei preso quell'insetto per un bel po 'di tempo se non avessi avuto quel test sul posto. Ed era un bug MOLTO brutto da avere. Fortunatamente, ho avuto il test e mi ha detto esattamente cosa dovevo fare per correggere il bug. Senza il test, avrei continuato a costruire il mio sistema (con il bug che infettava altri moduli che dipendevano da quel codice) e al momento della scoperta del bug sarebbe stato un compito importante risolverlo correttamente.

Il vero vantaggio di TDD è che ci consente di apportare modifiche con abbandono spericolato. È come una rete di sicurezza per la programmazione. Pensa a cosa succederebbe se un trapezista commettesse un errore e cadesse. Con la rete, è un errore imbarazzante. Senza, è una tragedia. Allo stesso modo, TDD ti evita di trasformare gli errori di testa in disastri che uccidono il progetto.


4
Il valore dei test rossi che rilevano i bug è un attributo del test unitario in generale, non specifico del TDD.
Robert Harvey,

2
Hai ragione su questo punto. Ma la probabilità che avrei avuto quel bug specifico coperto con test di unità post-hoc è inferiore.
Michael Brown,

1
Potete sostenere tale affermazione con alcune prove, dati o analisi solide?
CesarGon,

1
@CesarGon questo studio , mentre i programmatori lavorano su un piccolo progetto, suggeriscono che gli sviluppatori che usano TDD producono codice con una migliore copertura dei test rispetto a quelli che seguono i test (92% -98% contro 80% -90%) e conseguentemente catturano di più difetti durante lo sviluppo (18% in meno di difetti riscontrati nel codice prodotto utilizzando TDD).
Jules,

11

Non troverai nessuno che sostenga Test Driven Development, o nemmeno Test Driven Design (sono diversi), che afferma che i test dimostrano le applicazioni. Quindi chiamiamolo un uomo di paglia e fatti.

Non troverai nessuno a cui non piacciono o che non sono impressionati dal TDD che afferma che i test sono una perdita di tempo e fatica. Sebbene i test non provino le applicazioni, sono piuttosto utili nella ricerca di errori.

Detto questo, nessuna delle due parti sta facendo qualcosa di diverso per quanto riguarda l'esecuzione effettiva dei test sul software. Entrambi stanno facendo dei test. Entrambi si affidano ai test per trovare il maggior numero possibile di bug ed entrambi utilizzano i test per verificare che un programma software funzioni e che possa essere scoperto in quel momento. Nessuno con un mezzo indizio vende software senza test e nessuno con un mezzo indizio si aspetta che il test renderà il codice che vendono completamente privo di errori.

Quindi, la differenza tra TDD e non-TDD non sta nel fatto che i test sono in corso. La differenza sta nella scrittura dei test. Nei test TDD sono scritti PRIMA del software. Nei test non TDD sono scritti dopo o in concerto con il software.

Il problema che ho riscontrato in merito a quest'ultimo è che i test tendono quindi a indirizzare il software in fase di scrittura più del risultato o delle specifiche desiderate. Anche con il team di test separato dal team di sviluppo, il team di test tende a guardare il software, a giocarci e a scrivere test mirati.

Una cosa che è stata notata più volte da coloro che studiano il successo del progetto, è la frequenza con cui un cliente espone ciò che desidera, gli addetti allo sviluppo scappano e scrivono qualcosa e quando tornano dal cliente dicendo "fatto" risulta assolutamente e assolutamente NON quello che il cliente ha chiesto. "Ma supera tutti i test ..."

L'obiettivo di TDD è rompere questo "argomento circolare" e fornire la base per i test che testano il software che non è il software stesso. I test sono scritti per indirizzare il comportamento desiderato dal "cliente". Il software viene quindi scritto per superare quei test.

TDD fa parte della soluzione pensata per risolvere questo problema. Non è l'unico passo che fai. Altre cose che devi fare è assicurarti che ci sia più feedback dei clienti e più spesso.

Nella mia esperienza, TDD è una cosa molto difficile da implementare con successo. È difficile ottenere test scritti prima che ci sia un prodotto perché molti test automatici richiedono di avere qualcosa con cui giocare per far funzionare correttamente il software di automazione. È anche difficile convincere gli sviluppatori che non sono abituati ai test unitari a farlo. Di volta in volta ho detto alle persone del mio team di scrivere i test PRIMA. Non ne ho mai avuto uno che lo faccia. Alla fine, i vincoli di tempo e la politica hanno distrutto tutti gli sforzi in modo da non fare più nemmeno test unitari. Questo ovviamente porta inevitabilmente a un accoppiamento accidentale e grave del progetto, cosicché anche se lo volessimo, ora sarebbe proibitivamente costoso da implementare. Evitare QUELLO è ciò che TDD fornisce in definitiva agli sviluppatori.


+1 Grazie per la risposta esaustiva, Noah. Concordo sul fatto che la differenza principale tra TDD e non-TDD risiede nella scrittura dei test. Tuttavia, penso anche che la prima "D" in TDD sta per "guidato", il che significa che, in TDD, l'intero sviluppo è guidato dai test. Questo è ciò che trovo più sconcertante. Non ho problemi con la scrittura di test prima di costruire effettivamente ciò che verrà testato. Ma lasciare che i test guidino? In che modo è diverso da una luce verde fare qualsiasi cosa purché il superficiale (cioè il risultato) vada bene?
CesarGon,

Bene, Cesar, cosa proporresti come criterio migliore e oggettivo per decidere quando un compito di sviluppo è finito? Se, come in TDD, il test è la specifica che uno sviluppatore prende di mira, allora lo sviluppatore ha fatto il proprio lavoro quando il test ha superato, no? Sì, ci possono essere difetti nel test, proprio come possono esserci difetti in qualsiasi specifica. Tuttavia, non è compito degli sviluppatori risolvere. Se il test è imperfetto, viene riparato, quindi lo sviluppo ha come target il nuovo target e quando è tutto verde hanno finito. Funziona perché c'è SEMPRE un test da superare ... nessuna lanugine extra, non documentata.
Edward Strange,

3
Forse non mi sono espresso chiaramente. I test possono essere un buon modo per determinare quando hai finito. Ma non penso che siano un buon modo per decidere cosa devi costruire. E, in TDD, trovo che le persone stiano usando i test per decidere cosa dovrebbero costruire. Anche questa è la tua esperienza?
CesarGon,

No. Le nostre build sono automatizzate. Sono innescati da cambiamenti. Come ho detto, TDD è solo una parte della soluzione.
Edward Strange,

9

Progetta prima

TDD non è una scusa per saltare il design. Ho visto molti saltare nel carro "agile" perché pensavano che avrebbero potuto iniziare subito a scrivere codice. La vera agilità ti consentirà di codificare le statistiche molto più velocemente rispetto alle (buone pratiche) di ingegneria che hanno ispirato il processo a cascata.

Ma prova presto

Quando si afferma che il test sta guidando il progetto, significa semplicemente che è possibile utilizzare i test molto presto nella fase di progettazione, molto prima che sia completato. Fare questo test influenzerà fortemente il tuo progetto sfidando le aree grigie e confrontandolo con il mondo reale molto prima che il prodotto sia completato. costringendoti spesso a tornare al design e ad adattarlo per tenerne conto.

Test e progettazione ... lo stesso

Secondo me TDD porta semplicemente il test a essere parte integrante del design anziché qualcosa fatto alla fine per convalidarlo. Quando inizi a utilizzare TDD sempre di più, ti viene in mente come distruggere / rompere il tuo sistema mentre lo progetti. Personalmente non faccio sempre i miei test prima. Certo, eseguo i test (unità) ovvi su un'interfaccia, ma i vantaggi reali derivano dai test di integrazione e specifica che creo quando penso a un modo nuovo e creativo che questo design può interrompere. Non appena penso a un modo, codifico un test per questo e vedo cosa succede. A volte posso convivere con le conseguenze, in questo caso sposto il test in un progetto separato che non fa parte della build principale (poiché continuerà a fallire).

Allora chi guida lo spettacolo?

In TDD la guida qui significa semplicemente che i tuoi test influenzano così fortemente il tuo design che puoi sentire che lo stanno effettivamente guidando. Comunque ci si ferma a questo, e qui capisco le tue preoccupazioni, è un po 'spaventoso ... chi guida lo spettacolo?

Stai guidando, non i test. I test sono lì in modo tale che, man mano che avanzi, ottieni un buon livello di fiducia in ciò che hai creato, permettendoti di costruire ulteriormente sapendo che si basa su solidi motivi.

solido purché i test siano solidi

Esatto , da qui la spinta nel TDD. Non è tanto i test che guidano il tutto, ma avranno un'influenza così profonda su come fai le cose, su come progetti e pensi il tuo sistema che delegherai gran parte del tuo processo di pensiero ai test e in cambio avranno una profonda influenza sul tuo design.

si ma se lo faccio con il mio ponte th ....

fermati proprio lì ... l'ingegneria del software è MOLTO diversa da qualsiasi altra pratica ingegneristica là fuori. In effetti, l'ingegneria del software ha molto più in comune con la letteratura. Si può prendere un libro finito, strappare 4 capitoli da esso e scrivere due nuovi capitoli per sostituirli e rimetterli nel libro e hai ancora un buon libro. Con buoni test e software puoi strappare qualsiasi parte del tuo sistema e sostituirlo con un altro e il costo per farlo non è molto più alto di quello che lo stava creando in primo luogo. In effetti, se hai fatto i tuoi test e hai permesso loro di influenzare abbastanza il tuo design, potrebbe essere molto più economico che crearlo in primo luogo poiché avrai un certo livello di sicurezza che questa sostituzione non romperà ciò che i test stanno coprendo.

Se è così bello come mai non funziona sempre?

Perché i test richiedono una mentalità MOLTO diversa rispetto alla costruzione. Non tutti sono in grado di tornare indietro e da, in realtà alcune persone non saranno in grado di costruire test adeguati semplicemente perché non possono decidere di distruggere la loro creazione. Ciò produrrà progetti con troppi test o test sufficienti per raggiungere una metrica target (mi viene in mente la copertura del codice). Saranno felici test di percorso e test di eccezione, ma dimenticheranno i casi angolari e le condizioni al contorno.

Altri si limiteranno a fare affidamento sui test per rinunciare alla progettazione in tutto o in parte. Ogni membro che fa le sue cose si integra poi l'uno con l'altro. Il design è prima di tutto uno strumento di comunicazione, posta in gioco per dire che questo è dove sarò io, schizzi che dicono che questo è dove saranno le porte e le finestre. Senza questo il tuo software è destinato a prescindere da quanti test hai messo in atto. L'integrazione e le fusioni saranno sempre dolorose e mancheranno i test ai più alti livelli di astrazione.

Per questi team TDD potrebbe non essere la strada da percorrere.


7

Con TDD tendi a non scrivere codice che non sia facile o veloce da testare. Questo può sembrare una piccola cosa, ma può avere un profondo impatto su un progetto in quanto influisce sulla facilità con cui è possibile riformattare, testare, riprodurre bug con test e verificare correzioni.

È anche più facile per un nuovo sviluppatore del progetto aggiornarsi quando si dispone di un codice fattorizzato migliore supportato dai test.


2
Mi piace questo - sottolinea il fatto che non è così tanto TDD che crea i benefici (sebbene avere test unitari abbia chiaramente un enorme valore) come il tipo di codice che produce nel senso che è testabile (in isolamento) e ne derivano tutti i tipi di cose buone (separazione delle preoccupazioni, IoC e iniezione di dipendenza, ecc. ecc.)
Murph

1
@Murph yeah TDD ti aiuta a rimanere onesto :)
Alb

1
Ad essere onesti, in realtà non sono convinto dall'argomento "più facile da accelerare": i test possono essere utili, ma il codice (nel suo insieme, non necessariamente in isolamento) può essere un po 'più difficile da decodificare poiché alcune cose appare come per magia, ad esempio, non sai quale implementazione di IInjectedThing stai usando.
Murph,

@Murph La teoria è che l'implementazione IInjectedThing sia anche ben progettata e coperta da buoni test, quindi non è necessario sapere in cosa consiste essere in grado di comprendere una classe in cui viene iniettata.
Adam Lear

@Anna - sì, fino a un certo punto ... se stai cercando di capire dove qualcosa è rotto (ho sempre la sensazione che la caccia agli insetti sia un buon modo per trovare un piede in un progetto) o dove qualcosa deve essere cambiato / aggiunto che devi sapere dove. Anche se quello è ben incapsulato, devi ancora trovarlo ... e se significa sostituire qualcosa (nuova implementazione di IWhatsit), devi sapere come utilizzare l'implementazione alternativa. Ancora una volta, non sto confutando che la costruzione è cattiva - troppe prove del contrario - piuttosto suggerendo che alcune cose potrebbero essere meno ovvie.
Murph

5

Ci ho pensato molto, anche se non pratico molto il TDD da solo. Sembra esserci una correlazione (forte?) Positiva tra la qualità del codice e il successivo TDD.

1) La mia prima opinione è che questo non è dovuto principalmente al TDD che aggiunge "migliore qualità" al codice (in quanto tale), è più simile al TDD che aiuta a eliminare le parti e le abitudini peggiori, aumentando così indirettamente la qualità.

Vorrei anche sostenere che non è il test stesso: è il processo di scrittura di quei test. È difficile scrivere test per un codice errato e viceversa. E mantenendo questo nella parte posteriore della testa durante la programmazione, elimina molto codice errato.

2) Un altro punto di vista (sta diventando filosofico) sta seguendo le abitudini mentali del maestro. Non impari a diventare un maestro seguendo le sue "abitudini esterne" (come, una lunga barba è buona), devi imparare i suoi modi di pensare interni, e questo è difficile. E in qualche modo fare programmatori (principianti) seguire TDD, allineare i loro modi di pensare più vicini a quelli del maestro.


+1 Penso che tu l'abbia inchiodato, Maglob. Mi piace in particolare la tua spiegazione che "TDD aiuta a eliminare le parti e le abitudini peggiori, [...] aumentando indirettamente la qualità". E anche l'analogia della barba lunga è molto buona.
CesarGon,

non si scrivono test per un codice errato, ma si scrive un test e quindi si scrive il codice per far passare il test.

Maglob, per l'amore del lato più pratico delle cose, l'hai coperto al meglio. @ Thorbjørn, penso che Maglob si stia muovendo più lungo le linee che se il tuo progetto proiettato fa schifo, i tuoi test dovranno sicuramente risucchiare fino al livello di suckyness che i tuoi tentativi di materializzare e l'odore marcio di esso dovrebbe annusare nei tuoi test prima si arriva persino a scrivere qualsiasi codice reale.
Filip Dupanović,

3

L'approccio "write test + refactor till pass" sembra incredibilmente anti-ingegneria.

Sembra che tu abbia un'idea sbagliata sia del refactoring che del TDD.

Il refactoring del codice è il processo di modifica del codice sorgente di un programma per computer senza modificarne il comportamento funzionale esterno al fine di migliorare alcuni degli attributi non funzionali del software.

Quindi non puoi refactificare il codice fino a quando non passa.

E TDD, in particolare i test unitari (che considero il miglioramento di base, dal momento che altri test mi sembrano piuttosto plausibili), non si tratta di ridisegnare un componente fino a quando non funziona. Si tratta di progettare un componente e lavorare sull'implementazione fino a quando il componente funziona come previsto.

Inoltre è importante capire davvero che l' unità di prova riguarda le unità di prova . A causa della tendenza a scrivere sempre molte cose da zero, è importante testare tali unità. Un ingegnere civile conosce già le specifiche delle unità che utilizza (i diversi materiali) e può aspettarsi che funzionino. Queste sono due cose che spesso non si applicano agli ingegneri del software ed è molto pro-ingegneria testare le unità prima di usarle, perché significa utilizzare componenti testati di alta qualità.
Se un ingegnere civile avesse avuto l'idea di utilizzare un nuovo tessuto in fibra per realizzare un tetto per coprire uno stadio, ci si aspetterebbe che lo testasse come un'unità, cioè definire le specifiche necessarie (ad esempio peso, permeabilità, stabilità, ecc.) E successivamente testare e perfezionarlo fino a quando non li incontra.

Ecco perché TDD funziona. Perché se costruisci software di unità testate, è molto meglio che funzioni, collegandole e in caso contrario puoi aspettarti che il problema sia nel tuo codice colla, supponendo che i tuoi test abbiano una buona copertura.

modifica:
refactoring significa: nessun cambiamento nella funzionalità. Un punto di scrittura del test unitario è garantire che il refactoring non rompa il codice. Quindi TDD ha lo scopo di assicurare che il refactoring non ha effetti collaterali.
La granularità non è un argomento di prospettiva, perché come ho detto, l'unità testa le unità di test e non i sistemi, per cui la granularità è definita esattamente.

TDD incoraggia la buona architettura. Richiede di definire e implementare le specifiche per tutte le unità, costringendoti a progettarle prima dell'implementazione, il che è piuttosto il contrario di quello che sembra pensare. TDD determina la creazione di unità, che possono essere testate singolarmente e sono quindi completamente disaccoppiate.
TDD non significa che lancio un test del software al codice spaghetti e mescolo la pasta fino a quando non passa.

In contraddizione con l'ingegneria civile, nell'ingegneria del software un progetto di solito si evolve costantemente. Nell'ingegneria civile, hai il requisito di costruire un ponte in posizione A, che può trasportare x tonnellate ed è abbastanza largo per n veicoli all'ora.
Nell'ingegneria del software, il cliente può praticamente decidere in qualsiasi momento (possibilmente dopo il completamento), desidera un ponte a due piani e che lo desidera collegato con l'autostrada più vicina e che vorrebbe che fosse un ponte di sollevamento, perché la sua azienda recentemente ha iniziato a utilizzare le navi a vela.
Gli ingegneri del software hanno il compito di modificare i progetti. Non perché i loro disegni siano imperfetti, ma perché è il modus operandi. Se il software è ben progettato, può essere riprogettato ad alto livello, senza dover riscrivere tutti i componenti di basso livello.

TDD riguarda la creazione di software con componenti testati individualmente e altamente disaccoppiati. Ben eseguito, ti aiuterà a rispondere ai cambiamenti nei requisiti in modo significativamente più rapido e sicuro, che senza.

TDD aggiunge requisiti al processo di sviluppo, ma non proibisce altri metodi di garanzia della qualità. Certo, TDD non fornisce la stessa sicurezza della verifica formale, ma ancora una volta, la verifica formale è estremamente costosa e impossibile da utilizzare a livello di sistema. Eppure, se lo volessi, potresti combinare entrambi.

TDD comprende anche test diversi dai test unitari, eseguiti a livello di sistema. Trovo che siano facili da spiegare ma difficili da eseguire e difficili da misurare. Inoltre, sono abbastanza plausibili. Mentre vedo assolutamente la loro necessità, non li apprezzo davvero come idee.

Alla fine, nessuno strumento risolve effettivamente un problema. Gli strumenti semplificano solo la risoluzione di un problema. Puoi chiedere: come può uno scalpello aiutarmi con una grande architettura? Bene, se hai intenzione di fare pareti dritte, i mattoni dritti sono di aiuto. E sì, garantito, se dai questo strumento a un idiota, probabilmente alla fine lo sbatterà attraverso il piede, ma non è colpa dello scalpello, tanto che non è un difetto del TDD che dà falsa sicurezza ai principianti, chi non scrive buoni test.
Quindi, in sostanza, si può dire che TDD funziona molto meglio di nessun TDD.


Non penso di avere un'idea sbagliata; Sono d'accordo con la definizione di refactoring del codice che hai pubblicato, ma penso anche che devi esaminare la granularità delle modifiche nel codice. Quando si dice "il processo di modifica del codice sorgente di un programma per computer", è necessario rendersi conto che, dal punto di vista di un determinato insieme, il comportamento non cambia, ma cambia effettivamente il comportamento delle parti. Ecco come viene effettuato il cambiamento. Oltre a questo, ti ascolto sul perché TDD funziona (e lo condivido), ma come viene affrontata l'architettura secondo il mio post originale?
CesarGon,

@CesarGon: post aggiornato.
back2dos

2

Non mi piace che tu dica "il test, piuttosto che l'utente, stabilisce i requisiti". Penso che stai prendendo in considerazione solo i test unitari in TDD, mentre copre anche i test di integrazione.

Oltre a testare le librerie che costituiscono la base del software, scrivi i test che coprono le interazioni che i tuoi utenti hanno con il software / sito Web / qualunque cosa. Questi provengono direttamente dagli utenti e le librerie come il cetriolo (http://cukes.info) possono persino consentire ai tuoi utenti di scrivere i test da soli, in linguaggio naturale.

TDD incoraggia anche la flessibilità del codice: se impieghi per sempre a progettare l'architettura di qualcosa, sarà incredibilmente difficile apportare queste modifiche in seguito, se necessario. Inizia con la scrittura di un paio di test, quindi scrivi un piccolo codice che supera quei test. Aggiungi altri test, aggiungi più codice. Se è necessario modificare radicalmente il codice, i test restano validi.

E a differenza di ponti e automobili, un singolo software può subire enormi cambiamenti nel corso della sua vita, e fare refactoring complessi senza aver prima scritto i test richiede solo problemi.


Ti ho sentito dei vantaggi che richiedi per il TDD. Ma per quanto ho capito non affronti i problemi dell'architettura e non verifichi la qualità che chiedo esplicitamente nella mia domanda.
CesarGon,

@CesarGon: penso che le tue domande specifiche si applichino a qualsiasi tipo di test, non solo a TDD. Quindi mi sono concentrato solo sulle caratteristiche specifiche di TDD che "funzionano".
sevenseacat,

1
I test di integrazione hanno sicuramente più senso dei test unitari autonomi. La maggior parte dei casi di bug su cui inciampo non sarebbe mai stata trovata dai test unitari, solo testando l'intero sistema reale con tutti i suoi bulloni e fischietti in posizione.

2

Penso che ti stai avvicinando al primo punto da un'angolazione sbagliata.

Da un punto di vista teorico, stiamo dimostrando che qualcosa funziona controllando i punti di fallimento. Questo è il metodo usato. Potrebbero esserci molti altri modi per dimostrare che qualcosa è funzionale, ma TDD si è affermato grazie alla semplicità del suo approccio bit-saggio: se non si rompe funziona.

In pratica, questo si traduce semplicemente in: ora possiamo passare alla cosa successiva (dopo aver applicato con successo TDD per soddisfare tutti i predicati). Se ti avvicini a TDD da questa prospettiva, allora non si tratta di "scrivere test + refactor fino a passare", piuttosto di averlo completato, ora mi sto concentrando completamente sulla prossima funzione come la cosa più importante .

Pensa come questo si applica all'ingegneria civile. Stiamo costruendo uno stadio che può ospitare un pubblico di 150000 persone. Dopo aver dimostrato che l'integrità strutturale dello stadio è solida, abbiamo prima soddisfatto la sicurezza . Ora possiamo concentrarci su altre questioni che diventano immediatamente importanti, come servizi igienici, stand gastronomici, posti a sedere, ecc ... rendendo l'esperienza del pubblico più piacevole. Questa è una semplificazione eccessiva, in quanto c'è molto di più in TDD, ma il punto cruciale è che non fai la migliore esperienza dannatamente possibile se ti concentri su funzionalità nuove ed eccitanti e mantieni allo stesso tempo l'integrità. Lo ottieni a metà strada in entrambi i casi. Voglio dire, come puoi sapere esattamente comemolti servizi igienici e dove dovresti collocare per 150000 persone? Raramente ho visto crollare gli stadi durante la mia vita, ma ho dovuto aspettare in fila durante l'intervallo in così tante occasioni. Ciò afferma che il problema del gabinetto è probabilmente più complesso e se gli ingegneri possono dedicare meno tempo alla sicurezza, potrebbero finalmente essere in grado di risolvere il problema del gabinetto.

Il tuo secondo punto è irrilevante, perché abbiamo già concordato che gli assoluti sono uno sforzo folle e perché Hank Moody afferma che non esistono (ma non riesco a trovare un riferimento per questo).


+1 per una buona spiegazione del mio primo punto e per il riferimento a Hank Moody. Glorioso.
CesarGon,

2
Grazie, lo apprezzo. Vedo TDD più come un fenomeno psicologico, piuttosto che un approccio / processo tecnico. Ma questa è solo la mia visione del mondo sulla questione.
Filip Dupanović,

Sai esattamente quanti servizi igienici e dove dovrebbero essere collocati? La risposta è sì: vai a chiedere a qualsiasi architetto e ti diranno che queste informazioni sono fatte in anticipo e talvolta con dati statistici chiari per eseguirne il backup.
gbjbaanb,

1

TDD nell'ingegneria del software è una buona pratica, allo stesso modo della gestione degli errori nelle applicazioni, nonché della registrazione e della diagnostica (sebbene faccia parte della gestione degli errori).

TDD non deve essere utilizzato come strumento per ridurre lo sviluppo del software nella codifica di tentativi ed errori. Tuttavia, la maggior parte dei programmatori fissa registri di runtime, osserva le eccezioni nel debugger o utilizza altri segni di fallimento / successo durante la fase di sviluppo che consiste nella codifica / compilazione / esecuzione dell'app - per tutto il giorno.

TDD è solo un modo per formalizzare e automatizzare quei passaggi per renderti più produttivo come sviluppatore.

1) Non è possibile confrontare l'ingegneria del software con la costruzione di ponti, la flessibilità nella costruzione di ponti non è affatto simile a quella della progettazione di un programma software. Costruire il bridge è come scrivere lo stesso programma più volte in una macchina con perdite. I bridge non possono essere duplicati e riutilizzati come il software. Ogni ponte è unico e deve essere prodotto. Lo stesso vale per auto e altri design.

La cosa più difficile nell'ingegneria del software è la riproduzione dei guasti, quando un ponte si guasta di solito è molto facile determinare cosa è andato storto, ed è facile in teoria riprodurre il guasto. Quando un programma per computer non funziona, può trattarsi di una complessa catena di eventi che ha portato il sistema in uno stato difettoso e può essere molto difficile determinare dove si trova l'errore. TDD e unit test semplificano il test della robustezza di componenti software, librerie e algoritmi.

2) L'uso di test unitari deboli e casi di test poco profondi che non stressano il sistema per creare un falso senso di fiducia è solo una cattiva pratica. Ignorare la qualità architettonica di un sistema e semplicemente soddisfare i test è ovviamente altrettanto negativo. Ma imbrogliare sul posto di costruzione per un grattacielo o un ponte per risparmiare materiale e non seguire i progetti è altrettanto male e succede sempre ...


Non sono d'accordo con le tue implicazioni sul fatto che nei sistemi fisici (non software) sia facile riprodurre i guasti. Osserva, ad esempio, il lavoro estremamente complesso e duro necessario per determinare le cause profonde dei guasti meccanici negli incidenti del traffico aereo.
CesarGon,

Hm, ora stai confrontando un aereo di linea che si schianta con un ponte in avaria, un ponte di solito non può volare, case chiuso. Ma il confronto tra aeroplani e software è talvolta valido. Entrambe le aree sono molto complesse e richiedono una metodologia di prova strutturata. Quindi quando un ponte fallisce, sai che è stato sovraccaricato. Quando un aeroplano si schianta, ben sai che lo stato anormale di volare fuori terra è fallito, ma il motivo di solito richiede un'indagine approfondita lo stesso con un errore del software.
Ernelli,

I ponti possono essere duplicati - o almeno, il progetto del ponte acquistato dall'architetto può, all'incirca, apportare modifiche per adattarsi alle circostanze esatte. Il punto è che se hai bisogno di un ponte andrai dall'architetto e ti fornirà un elenco di pochi tipi che puoi avere - sospensione, scatola, arco ecc. E un elenco limitato di materiali per costruirlo.
gbjbaanb,

1

Se si accetta che prima vengono rilevati dei bug, minore è il costo per risolverli, quindi solo questo vale la pena TDD.


1
Hai qualche prova che i bug si trovano prima in un'impostazione TDD? Inoltre, che dire degli effetti collaterali del TDD, come l'impatto sull'architettura?
CesarGon,

0

TDD non riguarda davvero i test. E certamente non è un sostituto per buoni test. Ciò che ti dà è un design ben pensato, facile da consumare per il consumatore e facile da mantenere e refactoring in seguito. Queste cose a loro volta portano a un minor numero di bug e ad una progettazione software migliore e più adattabile. TDD ti aiuta anche a riflettere e documentare i tuoi presupposti, scoprendo spesso che alcuni di essi erano errati. Li scopri molto presto nel processo.

E come vantaggio secondario, hai una grande serie di test che puoi eseguire per assicurarti che un refactoring non cambi il comportamento (input e output) del tuo software.


6
-1. Molte persone continuano a dirlo, ma devo ancora vedere la magia che lo rende possibile.
Bart van Ingen Schenau,

@Bart van Ingen Schenau, hai fatto TDD? Lo faccio da circa 4 anni e ho sicuramente visto accadere la "magia".
Marcie,

0

Ti darò una breve risposta. Tipicamente TDD è visto nel modo sbagliato proprio come lo è il test unitario. Non ho mai capito i test unitari fino a poco tempo dopo aver visto un buon video di talk tecnico. Essenzialmente TDD sta semplicemente affermando che vuoi che le seguenti cose funzionino. DEVONO essere implementati. Quindi si progetta il resto del software come si farebbe normalmente.

È un po 'come scrivere casi d'uso per una biblioteca prima di progettare la biblioteca. Tranne che puoi cambiare il caso d'uso in una libreria e potresti non farlo per TDD (io uso TDD per la progettazione API). Sei anche incoraggiato ad aggiungere altri test e pensare a input / usi selvaggi che il test potrebbe ottenere. Lo trovo utile quando scrivo librerie o API in cui se cambi qualcosa devi sapere che hai rotto qualcosa. Nella maggior parte dei software quotidiani non mi preoccupo perché perché ho bisogno di un caso di test per un utente che preme un pulsante o se voglio accettare un elenco CSV o un elenco con una voce per riga ... Non importa davvero che io sia autorizzato per cambiarlo così non dovrei / non posso usare TDD.


0

Il software è organico, quando l'ingegneria strutturale è concreta.

Quando costruisci il tuo ponte, rimarrà un ponte ed è improbabile che si evolverà in qualcos'altro in un breve periodo di tempo. I miglioramenti verranno apportati nel corso di mesi e anni, ma non ore e giorni come nel software.

Quando si esegue il test in isolamento, normalmente sono disponibili due tipi di framework. Quadro vincolato e non vincolato. I framework non vincolati (in .NET) consentono di testare e sostituire tutto, indipendentemente dai modificatori di accesso. Cioè puoi stub e deridere componenti privati ​​e protetti.

La maggior parte dei progetti che ho visto utilizzano framework vincolati (RhinoMocks, NSubstitute, Moq). Quando si esegue il test con questi framework, è necessario progettare l'applicazione in modo tale da poter iniettare e sostituire le dipendenze in fase di esecuzione. Ciò implica che devi avere un design liberamente accoppiato. Il design liberamente accoppiato (se fatto bene) implica una migliore separazione delle preoccupazioni, il che è una buona cosa.

Per riassumere, credo che pensare dietro questo, sia che se il tuo progetto è testabile, quindi è vagamente accoppiato e ha una buona separazione delle preoccupazioni.

Da un lato, ho visto applicazioni davvero testabili, ma scarsamente scritte dal punto di vista del design orientato agli oggetti.


0

Perché TDD funziona?

Non

Chiarimento: i test automatizzati sono meglio di nessun test. Tuttavia, personalmente ritengo che la maggior parte dei test unitari siano sprechi perché di solito sono tautologici (ad esempio, dicono cose ovvie dal codice attuale in prova) e non si può facilmente dimostrare che siano coerenti, non ridondanti e coprano tutti i casi di frontiera (dove di solito si verificano errori ).

E la cosa più importante: una buona progettazione del software non cade magicamente dai test poiché è pubblicizzata da molti evangelisti agili / TDD. Tutti coloro che sostengono altrimenti forniscono collegamenti a ricerche scientifiche peer-reviewed che lo dimostrano, o almeno riferimento ad alcuni progetti open source in cui i benefici del TDD possono essere potenzialmente studiati dalla sua cronologia delle modifiche al codice.

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.