Perché funziona TDD? [chiuso]

92

Lo sviluppo basato sui test (TDD) è grande in questi giorni. Lo vedo spesso consigliato come 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 imbarazza per due ragioni:

  1. L'approccio "write test + refactor till pass" sembra incredibilmente anti-ingegneristico. Se gli ingegneri civili usassero questo approccio per la costruzione di ponti, o i progettisti di auto per le loro auto, per esempio, avrebbero rimodellato i loro ponti o le loro macchine a costi molto alti, e il risultato sarebbe un disastro rattoppato senza un'architettura ben congegnata . La linea guida "refactor till pass" è spesso presa come un mandato per dimenticare la progettazione architettonica e fare qualsiasi cosa sia necessaria per rispettare il test; in altre parole, il test, piuttosto che l'utente, imposta il requisito. In questa situazione, come possiamo garantire buoni "titoli" nei risultati, cioè un risultato finale che non è solo corretto ma anche estensibile, robusto, facile da usare, affidabile, sicuro, sicuro, ecc.? Questo è ciò che solitamente fa l'architettura.
  2. I test non possono garantire che un sistema funzioni; può solo mostrare che non è così. In altre parole, il test può mostrare che un sistema contiene dei difetti se fallisce un test, ma un sistema che supera tutti i test non è più sicuro di un sistema che li fallisce. La copertura del test, la qualità del test e altri fattori sono cruciali qui. I falsi sentimenti sicuri che un risultato "tutto verde" produce a molte persone sono stati segnalati nell'industria civile e aerospaziale come estremamente pericolosi, perché potrebbero essere interpretati come "il sistema va bene", quando in realtà significa "il sistema è buono come nostra strategia di test ". Spesso, la strategia di test non viene verificata. Oppure, chi prova 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.

Mi piacerebbe vedere le risposte contenenti i motivi per cui il TDD nell'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.

    
posta CesarGon 30.01.2011 - 14:17
fonte

19 risposte

66

Penso che ci sia un equivoco qui. Nel design del software, il design è molto vicino al prodotto. Nell'ingegneria civile, l'architettura, il design è disaccoppiato dal prodotto reale: ci sono progetti che mantengono il progetto, che vengono materializzati nel prodotto finito, e quelli sono separati da enormi quantità di tempo e sforzi.

TDD sta testando il design. Ma vengono testati anche tutti i design delle automobili e il design degli edifici. Le tecniche di costruzione vengono dapprima calcolate, quindi testate su scala ridotta, quindi testate su più grande scala, prima di essere messe in un edificio reale. Ad esempio, quando hanno inventato i fasci H e il carico, si è assicurato che questo sia stato provato e provato di nuovo prima che realizzasse effettivamente il primo ponte con esso.

Anche i design delle auto vengono testati, progettando prototipi e sì, certamente adeguando le cose che non sono esattamente giuste, fino a quando non è all'altezza delle aspettative. Parte di questo processo è però più lenta, perché come hai detto tu non puoi scherzare molto con il prodotto. Ma ogni riprogettazione di un'auto si basa su esperienze apprese da precedenti, e ogni edificio ha circa un centinaio di anni di fondamenti dietro l'importanza dell'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 sono testate. Forse non esattamente nello stesso stile del software, ma le parti meccaniche (ruote, accenditori, cavi) sono solitamente misurate e messe sotto stress per sapere che le dimensioni sono corrette, non si vedono anomalie, ecc. Potrebbero essere radiografate o laser- misurati, toccano i mattoni per individuare quelli danneggiati, potrebbero essere effettivamente testati in qualche configurazione o altro, oppure disegnano una rappresentazione limitata di un grande gruppo per metterlo alla prova.

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

E infatti, il test non è garanzia. I programmi si bloccano, le macchine si rompono e gli edifici iniziano a fare cose divertenti quando soffia il vento. Ma ... '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 ed è fragile e si rompe al primo colpo di martello quando metti la tua struttura principale è un semplice spreco di denaro. Che ci siano altre preoccupazioni che potrebbero ancora danneggiare l'edificio non renderlo meno stupido per consentire a un difetto facilmente prevenibile di abbattere il tuo design.

Per quanto riguarda la pratica del TDD, è una questione di equilibrio. Il costo di farlo in un modo (ad esempio, non testare, e quindi raccogliere i pezzi più tardi), 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.

    
risposta data 30.01.2011 - 15:02
fonte
25

IMO, la maggior parte delle storie di successo per TDD sono false e solo per scopi di marketing. Ci può essere molto poco successo con esso, ma solo per le 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 testabili a causa delle complesse interazioni dell'utente. Test risultanti con molti mock e codice difficile da capire.

Inizialmente, quando abbiamo provato TDD, tutto sembra buono. Sono stato in grado di scrivere molti test e prendere in giro le parti che sono difficili per un test unitario. Una volta che hai una buona quantità di codice e è necessaria 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: What about the idea of using tests to drive design?

Norvig: I see tests more as a way of correcting errors rather than as a way of design. This extreme approach of saying, “Well, the first thing you do is write a test that says I get the right answer at the end,” and then you run it and see that it fails, and then you say, “What do I need next?”—that doesn’t seem like the right way to design something to me. It seems like only if it was so simple that the solution was preordained would that make sense. I think you have to think about it first. You have to say, “What are the pieces? How can I write tests for pieces until I know what some of them are?” And then, once you’ve done that, then it is good discipline to have tests for each of those pieces and to understand well how they interact with each other and the boundary cases and so on. Those should all have tests. But I don’t think you drive the whole design by saying, “This test has failed.”

    
risposta data 31.01.2011 - 07:28
fonte
24

Test Driven Design funziona per me per i seguenti motivi:

È una forma eseguibile delle specifiche.

Questo significa che puoi vedere dai casi di test:

  1. CHE il codice che viene chiamato completa riempie la specifica in quanto i risultati attesi sono proprio lì nei casi di test. L'ispezione visiva (che si aspetta che i test vengano superati) può dire immediatamente "oh, questo test controlla che la fattura di chiamata, considerando questa situazione, debba avere QUESTO risultato".
  2. COME il codice dovrebbe essere chiamato. I passaggi effettivi necessari per eseguire i test sono specificati direttamente senza alcun ponteggio esterno (i database sono presi in giro, ecc.).

Scrivi prima la vista dall'esterno.

Spesso il codice è scritto in modo da prima risolvere il problema, e poi pensi a come il codice che hai appena scritto deve essere chiamato. Questo spesso fornisce un'interfaccia scomoda perché è spesso più facile "aggiungere una bandiera" ecc. Pensando al "dobbiamo fare QUESTO in modo che i testicoli sembrino così" in anticipo, si capovolge. Ciò fornirà una migliore modularità, in quanto il codice verrà scritto in base all'interfaccia di chiamata, non il contrario.

Di solito ciò comporta anche un codice più pulito che richiede una documentazione meno esplicativa.

Hai finito più velocemente

Dato 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 del progresso molto chiaro e visibile e quando hai finito.

Questo significa che puoi dire quando il lavoro è necessario o meno (aiuta a superare un test) e alla fine devi fare meno.

Per chi medita su questo può essere utile per loro, ti incoraggio a usare TDD per la tua prossima routine di libreria. Imposta lentamente una specifica eseguibile e fai passare il codice ai test. Al termine, la specifica eseguibile è disponibile per tutti coloro che devono vedere come richiamare la libreria.

Studio recente

"I risultati degli studi di casi indicano che la densità dei difetti pre-rilascio dei quattro prodotti è diminuita tra il 40% e il 90% rispetto a progetti simili che non hanno utilizzato la pratica TDD. % di aumento del tempo di sviluppo iniziale dopo l'adozione di TDD. " ~ Risultati ed esperienze di 4 team industriali

    
risposta data 30.01.2011 - 17:57
fonte
19

Il processo di creazione del software non è il processo di scrittura del codice. Nessun progetto software dovrebbe iniziare prima senza un piano di 'ampio raggio'. Proprio come un progetto di colmare due sponde di un fiume ha bisogno prima di tutto di un piano.

L'approccio TDD si riferisce (principalmente) al test delle unità - almeno questo è il modo in cui le persone tendono a pensarci - che sta creando il bit più basso del codice del software. Quando tutte le caratteristiche e i comportamenti sono già stati definiti e sappiamo effettivamente cosa vogliamo raggiungere.

In ingegneria strutturale sembra un po 'come questo:

'We have these two pieces of metal connected together, and the connection needs to sustain shear forces in the order of x. Let's test which connection method is the best one to do this'

Per testare 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 l'effettivo lavoro di scrittura del codice e vengano eseguiti dopo che i test unitari sono verdi.

Vedi V-Model: link

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'importo totale (o alcuno) denaro, se non può superare quel test.

  2. La gestione della società decide sulla pianificazione del progetto. Istituiscono gruppi di lavoro e stabiliscono 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 qualche problema, l'azienda può compensare questo cambiando i requisiti, cambiando subappaltatori, assumendo più persone ecc. In modo che l'intero progetto soddisfi ancora l'obiettivo impostato al punto # 1.

  3. All'interno di un team responsabile della progettazione di particolari componenti del bridge, è come nell'esempio che ho fornito sopra. A volte la soluzione è ovvia, perché abbiamo una grande quantità di conoscenze relative alla creazione di bridge (è come usare una libreria ben testata nello sviluppo del software - si presume che funzioni come pubblicizzato). A volte è necessario creare diversi progetti e testarli per scegliere il migliore. Tuttavia, i criteri su cui viene testato il componente sono noti in anticipo.

risposta data 30.01.2011 - 14:24
fonte
18

Nella mia mente TDD funziona perché

  • Ti obbliga a definire ciò che vuoi che l'unità faccia prima di decidere sull'implementazione a un livello di precisione generalmente non coperto da alcun documento sulle specifiche o sui requisiti
  • Rende il tuo codice intrinsecamente riutilizzabile, perché devi usarlo sia in test che in scenari di produzione
  • Ti incoraggia a scrivere codice in un eaiser più piccolo per testare blocchi che tendono a portare a disegni migliori

Specificamente sui punti che hai sollevato

  • Il codice è più malleabile del mattone o dell'acciaio, quindi è più economico da modificare. È ancora più economico se hai dei test per garantire che il comportamento non sia cambiato
  • TDD non è una scusa per non progettare: un'architettura di alto livello è generalmente ancora consigliata, ma non con troppi dettagli. Il design di Big Up Front è scoraggiato, ma è sufficiente incoraggiare il design
  • TDD non è in grado di garantire che un sistema funzioni, ma evita che si verifichino molti piccoli errori che altrimenti verrebbero persi. Inoltre, poiché in genere incoraggia un codice fattorizzato migliore, è spesso più facile da comprendere, quindi è meno probabile che sia infestato
risposta data 30.01.2011 - 16:19
fonte
16

TL; DR

La programmazione è ancora un'attività di progettazione, non è costruzione. Scrittura di 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 individuare gli errori in anticipo.

Il codice è design

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

La cosa interessante di questa argomentazione è che egli sottolinea che, a differenza di altre discipline ingegneristiche in cui la costruzione è un'attività molto costosa, la costruzione del software è relativamente gratuita (esegui la compilazione nel tuo IDE e hai il software costruito). Se si visualizza il codice di scrittura come un'attività di progettazione anziché un'attività di costruzione, il ciclo di refactore rosso-verde è fondamentalmente un esercizio di progettazione. Il tuo progetto si evolve man mano che scrivi test, il codice per soddisfarli e refactoring per integrare il nuovo codice nel sistema esistente.

TDD come specifica

I test unitari che scrivi per TDD sono una traduzione diretta delle specifiche come li capisci. Scrivendo un codice che soddisfi in minima parte le tue specifiche (rende i tuoi test verdi), tutto il codice che hai scritto è lì per uno scopo specifico. Che lo scopo sia stato raggiunto o meno è convalidato da un test ripetibile.

Scrivi test sulla funzionalità

Un errore comune nei test delle unità si verifica quando si scrivono i test dopo il codice, si finisce col 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 semplice proprietà). Non serve per convalidare una specifica. E come hai detto, scrivere questo tipo di test ti porta solo lontano.

Mentre il verde è buono, il valore si trova in rosso Ho avuto il mio primo vero "aha" momento in TDD quando ho avuto un fallimento inaspettato. Avevo una serie di test che avevo per un framework che stavo costruendo. Aggiungendo una nuova funzione, ho scritto un test per questo. Quindi ha scritto il codice per far passare il test. Compilare, testare ... avere un green sul nuovo test. Ma ho anche ottenuto un rosso su un altro test che non mi aspettavo di diventare rosso.

Guardando al fallimento, respiro un sospiro di sollievo perché dubito che avrei catturato quel bug per un po 'di tempo se non avessi fatto quel test. Ed è stato un bug molto brutto avere. Fortunatamente, ho fatto 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 nel momento in cui il bug è stato scoperto, sarebbe stato un compito importante correggerlo 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 a capo di ossa in disastri per uccidere progetti.

    
risposta data 31.01.2011 - 18:44
fonte
11

Non troverai nessuno che sostenga il Test Driven Development, o anche il Test Design (sono diversi), che dice che i test dimostrano le applicazioni. Quindi lascia che chiami un uomo di paglia e faccia.

Non troverai nessuno a cui non piaccia o non sia colpito da TDD che dice che i test sono una perdita di tempo e fatica. Sebbene i test non dimostrino le applicazioni, sono abbastanza utili per trovare errori.

Con queste due cose dette, nessuna delle due parti sta facendo qualcosa di diverso per quanto riguarda i test effettivamente eseguiti sul software. Entrambi stanno facendo test. Entrambi RILANCIAvano i test per trovare il maggior numero possibile di errori e utilizzano entrambi i test per verificare che un programma software funzioni correttamente e possa essere scoperto al momento. Nessuno con un mezzo indizio vende software senza test e nessuno con un mezzo indizio si aspetta che i test rendano il codice che vendono completamente privo di bug.

Quindi, la differenza tra TDD e non-TDD non è che si stiano facendo dei test. La differenza è quando i test sono scritti. Nei test TDD vengono scritti PRIMA del software. Nei test non-TDD vengono scritti dopo o in concerto con il software.

Il problema che ho riscontrato relativamente a quest'ultimo è che i test tendono a indirizzare il software a essere scritto più del risultato desiderato o delle specifiche. Anche con il team di test separato dal team di sviluppo, il team di testing tende a guardare il software, a giocare con esso e a scrivere test mirati.

Una cosa che è stata notata più e più volte da coloro che studiano il successo del progetto, è la frequenza con cui un cliente esporrà ciò che desidera, lo sviluppo che le persone scappano e scrivono qualcosa e quando tornano al cliente dicendo "fatto" risulta essere completamente e completamente NON quello che il cliente ha chiesto. "Ma passa 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 vengono scritti per individuare il comportamento desiderato dal "cliente". Il software viene quindi scritto per superare quei test.

TDD è 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 da parte dei clienti e più spesso.

Nella mia esperienza però, TDD è una cosa molto difficile da implementare con successo. È difficile fare 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 ottenere sviluppatori che non sono abituati a testare l'unità per farlo. Più volte ho detto alla gente della mia squadra di scrivere i test PRIMA. Non ne ho mai avuto uno per farlo. Alla fine, i vincoli temporali e la politica hanno distrutto tutti gli sforzi in modo che non facciamo più nemmeno test unitari. Ciò, naturalmente, ha comportato inevitabilmente un'accoppiata accidentale del progetto, in modo tale che, anche volendolo, sarebbe ora proibitivo implementarlo. Evitare THAT è ciò che TDD alla fine fornisce agli sviluppatori.

    
risposta data 30.01.2011 - 21:50
fonte
9

Design prima

TDD è non una scusa per saltare il design. Ho visto molti salti sul carro "agile" perché loro, sebbene potessero iniziare immediatamente a scrivere codice. La vera agilità ti porterà alla codifica statica molto più velocemente rispetto alle buone pratiche di ingegneria (altro campo) che hanno ispirato il processo a cascata.

Ma prova presto

Quando si dice che il test sta guidando il progetto significa semplicemente che si possono usare i test molto presto nella fase di progettazione, molto prima che sia completo. Fare questi test influenzerà strongmente il tuo design sfidando le aree grigie e mettendole contro il mondo reale molto prima che il prodotto sia completato. costringendoti spesso a tornare a progettare e ad adattarlo per tenerne conto.

Testa e disegna ... lo stesso

Secondo me TDD semplicemente porta il test ad essere una parte integrale del design invece di qualcosa fatto alla fine per convalidarlo. Quando inizi a utilizzare TDD, tieni sempre presente la mentalità su come distruggere / rompere il tuo sistema mentre lo progetta. Personalmente non faccio sempre i miei test prima. Certo, eseguo i test (unitari) evidenti su un'interfaccia, ma i veri vantaggi derivano dai test di integrazione e specifica che creo quando penso a un modo nuovo e creativo di rompere questo design. Non appena penso a un modo, codifico un test per questo e vedo cosa succede. A volte posso vivere con le conseguenze, in questo caso sposto il test in un progetto separato che non fa parte della build principale (dato che continuerà a fallire).

Allora chi guida lo spettacolo?

Nel TDD qui guidato significa semplicemente che i tuoi test influenzano così strongmente il tuo design che uno può sentire che lo sta effettivamente guidando. Comunque si ferma a quello, e qui capisco le tue preoccupazioni, è un po 'spaventoso ... chi guida lo spettacolo?

TU stai guidando, non i test. I test sono lì in modo che man mano che ti sposti ottieni un buon livello di fiducia in ciò che hai creato, permettendoti così di costruire ulteriormente sapendo che poggia su basi solide.

solido fino a quando i test sono solidi

Esatto , da cui deriva il TDD. Non sono tanto i test che guidano il tutto, ma avranno un'influenza così profonda su come si fanno le cose, su come si progetta e si pensa al proprio sistema che si delegherà una grossa parte del processo di pensiero ai test e in cambio avranno una profonda influenza sul tuo design.

sì, ma se lo faccio con il mio bridge th ....

basta fermarsi lì ... l'ingegneria del software è MOLTO diversa da qualsiasi altra pratica di ingegneria 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 e scrivere due nuovi capitoli per rimpiazzarli, rimetteteli nel libro e avete ancora un buon libro. Con buoni test e software puoi strappare qualsiasi parte del tuo sistema e sostituirlo con un altro e il costo di farlo non è molto più alto di quello che stava creando in primo luogo. Infatti, se hai fatto i tuoi test e hai permesso loro di influenzare il tuo design abbastanza potrebbe essere molto più economico che crearlo, in primo luogo, dal momento che avrai un certo livello di sicurezza nel fatto che questa sostituzione non infrangerà 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, in effetti, alcune persone non saranno in grado di costruire test appropriati semplicemente perché non possono decidere di distruggere la loro creazione. Ciò produrrà progetti con troppo pochi test o test appena sufficienti per raggiungere una metrica target (la copertura del codice viene in mente). Saranno felici test su strada e test delle eccezioni, ma dimenticheranno i casi d'angolo e le condizioni al contorno.

Gli altri faranno semplicemente affidamento su test che abbandonano il design in parte o del tutto. Ogni membro che fa è una cosa che si integra con l'un l'altro. Il design è prima di tutto uno strumento di comunicazione, posta in gioco per dire che questo è il posto dove andrò, abbozzi che dicono che questo è dove saranno le porte e le finestre. Senza questo il tuo software è condannato a prescindere dal numero di test che hai inserito. L'integrazione e le fusioni saranno sempre dolorose e mancheranno test ai più alti livelli di astrazione.

Tor queste squadre TDD potrebbe non essere la strada da percorrere.

    
risposta data 21.10.2011 - 05:17
fonte
7

Con TDD tendi a non scrivere codice non facile o veloce da testare. Può sembrare una cosa piccola, ma può avere un impatto profondo su un progetto in quanto influisce sulla facilità con cui refactoring, test, riproduzione di bug con test e verifiche.

È anche più semplice per un nuovo sviluppatore del progetto essere al passo con la velocità quando hai un codice fattorizzato meglio supportato dai test.

    
risposta data 30.01.2011 - 15:04
fonte
5

Ci ho pensato molto, anche se non pratico molto TDD. Sembra esserci una (strong?) Correlazione positiva tra la qualità del codice e il successivo TDD.

1) La mia prima opinione è che, (principalmente) non è dovuto a TDD che aggiunge "qualità migliore" al codice (come tale), è più simile a 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 scrivere quei test. È difficile scrivere test per un codice errato e viceversa. E mantenendo questo nella parte posteriore della testa durante la programmazione, elimina un sacco di codice errato.

2) Un altro punto di vista (questo 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 i programmatori (alle prime armi) seguono il TDD, allineano i loro modi di pensare più vicini a quelli del maestro.

    
risposta data 30.01.2011 - 16:04
fonte
3

The "write test + refactor till pass" approach looks incredibly anti-engineering.

Sembra che tu abbia un equivoco sia sul refactoring che sul TDD.

Code refactoring is the process of changing a computer program's source code without modifying its external functional behavior in order to improve some of the nonfunctional attributes of the software.

Quindi non puoi refactare codice fino a quando non passa.

E il TDD, in particolare il test delle unità (che considero il miglioramento principale, dal momento che altri test mi sembrano piuttosto plausibili), non riguarda la riprogettazione di un componente finché non funziona. Si tratta di progettare un componente e di lavorare sull'implementazione fino a quando il componente non funziona come progettato.

Inoltre, è importante comprendere bene che il test dell'unità riguarda il test delle unità . 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 usa (i diversi materiali) e può aspettarsi che funzionino. Queste sono due cose che spesso non si applicano agli ingegneri del software, ed è molto pro-ingegneristico testare le unità prima di usarle, perché significa utilizzare componenti testati e di alta qualità.
Se un ingegnere civile aveva l'idea di usare del nuovo tessuto in fibra per fare un tetto per coprire un stadio, ti aspetteresti che provi come unità, cioè definisci le specifiche necessarie (ad esempio peso, permeabilità, stabilità, ecc.) e successivamente prova e raffina fino a quando non le incontra.

Ecco perché TDD funziona. Perché se costruisci software di unità testate, è molto meglio che funzioni, quando le colleghi e se non ci si può aspettare che il problema sia nel codice della colla, supponendo che i tuoi test abbiano una buona copertura.

modifica
Refactoring significa: no modifica delle funzionalità. Un punto di test dell'unità di scrittura è garantire che il refactoring non infranga 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, unit test prova unità e non sistemi, per cui la granularità è esattamente definita.

TDD incoraggia una buona architettura. Ti richiede di definire e implementare le specifiche per tutte le tue unità, costringendoti a progettarle prima dell'implementazione, il che è esattamente il contrario di ciò che sembri pensare. TDD detta la creazione di unità, che possono essere testate individualmente e quindi completamente disaccoppiate.
TDD non significa che lancio un test del software con spaghetti code 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 l'obbligo di costruire un ponte in posizione A, che può trasportare tonnellate di tonnellate ed è abbastanza largo per n veicoli all'ora.
Nell'ingegneria del software, il cliente può decidere in qualsiasi momento (eventualmente dopo il completamento), vuole un ponte a due corsie, e che lo vuole collegato all'autostrada più vicina e che gli piacerebbe che fosse un ponte di sollevamento, perché la sua azienda recentemente ha iniziato a usare le navi a vela.
I tecnici del software sono incaricati di modificare i progetti. Non perché i loro disegni sono difettosi, ma perché questo è 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 singolarmente e strongmente disaccoppiati. Ben eseguito, ti aiuterà a rispondere ai cambiamenti dei requisiti significativamente più veloci e sicuri, che senza.

TDD aggiunge requisiti al processo di sviluppo, ma non vieta altri metodi di assicurazione della qualità. Certo, TDD non fornisce la stessa sicurezza della verifica formale, ma poi di nuovo, la verifica formale è estremamente costosa e impossibile da usare a livello di sistema. Eppure, se lo si desidera, è possibile combinare entrambi.

TDD comprende anche test diversi dai test unitari, che vengono 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 considero davvero come idee.

Alla fine, nessuno strumento in realtà risolve un problema. Gli strumenti rendono solo la soluzione di un problema più semplice. Puoi chiedere: in che modo uno scalpello mi può aiutare con una grande architettura? Beh, se hai intenzione di fare muri dritti, i mattoni dritti sono di aiuto. E sì, scontato, se dai a quell'idiota quello strumento, probabilmente lo sbatterà al piede, ma non è colpa dello scalpello, per quanto non sia un difetto del TDD che dia sicurezza ai novizi, chi non scrive buoni test.
Quindi, alla fine, si può dire che TDD funziona molto meglio di nessun TDD.

    
risposta data 31.01.2011 - 13:59
fonte
2

Non mi piace che tu dica "il test, piuttosto che l'utente, imposta i requisiti". Penso che tu stia considerando solo i test unitari in TDD, mentre riguarda 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 / qualsiasi cosa. Questi provengono direttamente dagli utenti e le biblioteche come cetriolo (http://cukes.info) possono persino consentire agli utenti di scrivere i test stessi, in un linguaggio naturale.

TDD incoraggia anche la flessibilità nel codice: se spendi per sempre a progettare l'architettura di qualcosa, sarà estremamente difficile apportare tali 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 altro codice. Se hai bisogno di cambiare radicalmente il codice, i tuoi test rimangono validi.

E a differenza dei bridge e delle automobili, un singolo software può subire enormi cambiamenti nel corso della sua durata, e fare complessi refactoring senza aver prima scritto i test è solo chiedendo per problemi.

    
risposta data 30.01.2011 - 14:36
fonte
2

Penso che ti stai avvicinando al primo punto dall'angolo sbagliato.

Da un punto di vista teorico, stiamo dimostrando che qualcosa funziona controllando i punti di errore. 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 funziona, funziona.

In pratica, questo si traduce semplicemente in modo esplicito: ora possiamo passare alla prossima (dopo aver applicato con successo TDD per soddisfare tutti i predicati). Se ti avvicini a TDD da questa prospettiva, allora non si tratta di "test di scrittura + refattore fino al passaggio", ma è più che altro su averlo completato, ora mi concentro interamente sulla prossima funzione come la cosa più importante ora .

Pensa a come si applica all'ingegneria civile. Stiamo costruendo uno stadio in grado di ospitare un pubblico di 150000 persone. Dopo aver dimostrato che l'integrità strutturale dello stadio è solida, abbiamo soddisfatto la sicurezza prima . Ora possiamo concentrarci su altre questioni che diventano immediatamente importanti, come gabinetti, stand gastronomici, posti a sedere, ecc. Rendendo l'esperienza del pubblico più piacevole. Questa è una semplificazione eccessiva, poiché c'è molto di più in TDD, ma il punto cruciale è che non si ottiene la migliore esperienza utente dannata se ci si concentra su nuove ed entusiasmanti funzionalità e allo stesso tempo mantenere l'integrità. Lo ottieni a metà strada in entrambi i casi. Voglio dire, come puoi sapere esattamente come molti gabinetti e dove dovresti piazzare per 150000 persone? Raramente ho visto gli stadi crollare nel corso della mia vita, ma ho dovuto aspettare in fila durante la metà del tempo in così tante occasioni. Ciò significa che il problema del lavabo è probabilmente più complesso e se gli ingegneri possono dedicare meno tempo alla sicurezza, potrebbero finalmente essere in grado di risolvere il problema del lavabo.

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

    
risposta data 31.01.2011 - 00:56
fonte
1

Il TDD nell'ingegneria del software è una buona pratica, allo stesso modo in cui la gestione degli errori nelle applicazioni è buona pratica così come la registrazione e la diagnostica (sebbene faccia parte della gestione degli errori).

TDD non deve essere usato come strumento per ridurre lo sviluppo del software in trial & codifica degli errori. Tuttavia, molti programmatori fissano i registri di runtime, guardano le eccezioni nel debugger o usano altri segni di insuccesso / successo durante la loro fase di sviluppo che consiste nella codifica / compilazione / esecuzione dell'app - per tutto il giorno.

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

1) Non è possibile confrontare l'ingegneria del software per costruire un ponte, la flessibilità nella costruzione del ponte non è affatto vicina a quella di progettare un programma software. Costruire il ponte è come scrivere lo stesso programma più e più volte in una macchina smarrita. I bridge non possono essere duplicati e riutilizzati come il software può. Ogni ponte è unico e deve essere prodotto. Lo stesso vale per le automobili e altri design.

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

2) Usare test di unità deboli e casi di test superficiali che non sottolineano 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 grave. Ma barare sul luogo di costruzione di un grattacielo o di un ponte per salvare materiale e non seguire i progetti è altrettanto brutto e succede sempre ...

    
risposta data 30.01.2011 - 16:47
fonte
1

Se accetti che prima vengono rilevati i bug, meno il costo di risolverli, allora questo vale da solo per TDD.

    
risposta data 30.01.2011 - 23:38
fonte
0

TDD non si tratta di test. E certamente non sostituisce i buoni test. Quello che ti dà è un design che è 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 ea un design del software migliore e più adattabile. TDD ti aiuta anche a pensare e documentare le tue ipotesi, spesso scoprendo che alcune di esse erano errate. Li trovate molto presto nel processo.

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

    
risposta data 30.01.2011 - 17:25
fonte
0

Ti darò una risposta breve. In genere TDD è guardato nel modo sbagliato, proprio come lo è il test unitario. Non ho mai capito i test unitari fino a poco tempo fa dopo aver visto un bel video parlato. Essenzialmente TDD sta semplicemente affermando che vuoi che LAVORANO le seguenti cose. DEVONO essere implementati. Quindi progetterai il resto del software come faresti normalmente.

Il suo tipo di scrittura simile usa casi per una biblioteca prima di progettare la libreria. Tranne che è possibile modificare il caso d'uso in una libreria e non si può per TDD (io uso TDD per la progettazione dell'API). Si è anche incoraggiati ad aggiungere altri test e pensare a input / usi selvaggi che il test potrebbe ottenere. Trovo utile quando si scrivono librerie o API in cui, se si modifica qualcosa, è necessario sapere che si è rotto qualcosa. Nella maggior parte dei software giorno per giorno non mi preoccupo perché ho bisogno di un caso di test per un utente che preme un pulsante o se voglio accettare una lista CSV o una lista con una voce per linea ... Non importa davvero che io sia permesso per cambiarlo quindi non dovrei / non posso usare TDD.

    
risposta data 21.10.2011 - 10:13
fonte
0

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

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

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

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

Per riassumere, credo che pensare in questo modo sia che se il tuo progetto è testabile, quindi è strettamente collegato e ha una buona separazione delle preoccupazioni.

Da una nota a margine, ho visto applicazioni che erano realmente testabili, ma scritte male dal punto di vista del design orientato agli oggetti.

    
risposta data 06.05.2014 - 11:30
fonte
0

Why does TDD work?

Non è così.

Chiarificazione: i test automatici sono migliori di nessun test. Tuttavia, personalmente ritengo che la maggior parte dei test unitari siano sprechi perché di solito tautologici (cioè ovvi dal codice reale in prova) e non si può facilmente dimostrare che siano coerenti, non ridondanti e coprano tutti i casi di confine (dove si verificano di solito errori ).

E la cosa più importante: il buon design del software non cade magicamente dai test in quanto è pubblicizzato da molti evangelisti agili / TDD. Chiunque rivendichi altrimenti, si prega di fornire collegamenti a ricerche scientifiche sottoposte a revisione paritaria, come dimostra questo, o almeno di fare riferimento ad alcuni progetti open source in cui i benefici del TDD possono essere potenzialmente studiati attraverso la cronologia delle modifiche al codice.

    
risposta data 10.11.2014 - 21:30
fonte

Leggi altre domande sui tag