Quali sono gli svantaggi della scrittura del codice prima di scrivere unit test?


33

Ho sempre visto la raccomandazione che dovremmo prima scrivere unit test e poi iniziare a scrivere codice. Ma penso che andare dall'altra parte sia molto più comodo (per me) - scrivere il codice e poi i test unitari, perché sento che abbiamo molta più chiarezza dopo aver scritto il codice attuale. Se scrivo il codice e quindi i test, potrei dover modificare un po 'il mio codice per renderlo testabile, anche se mi concentro molto sulla creazione di un design verificabile. D'altra parte, se scrivo i test e quindi il codice, i test cambieranno abbastanza frequentemente man mano che il codice si forma.

Dato che vedo molti consigli per iniziare a scrivere test e poi passare alla codifica, quali sono gli svantaggi se lo faccio nell'altro modo: scrivere codice e quindi i test unitari?


7
+1 per aver chiesto perché una determinata pratica sia una "best practice" prima di abbracciarla
TaylorOtwell

Risposte:


37

Il rosso è la risposta. Il rosso è ciò che ottieni dal ciclo rosso-verde-refattore di TDD che non puoi ottenere, test-last. Innanzitutto, scrivi un test non riuscito. Guarda fallire. Questo è il tuo rosso ed è importante. Dice: ho questo requisito e io so che il mio codice non lo soddisfa. Quindi, quando vai al passaggio 2 (verde), sai, con altrettanta certezza, che il tuo codice ora soddisfa tale requisito. Sai che hai modificato la tua base di codice in modo tale da soddisfare il requisito.

I requisiti (test) sviluppati dopo il codice, basati sul codice, ti privano di quel tipo di certezza, di quella sicurezza.


+1 - ottimo punto e punto preso! Grazie per la tua opinione!
k25,

7
Test! = Requisiti. Sia i test che il codice devono essere derivati ​​dai requisiti.
Bart van Ingen Schenau,

2
@Bart van Ingen Schenau: Il punto di forza del TDD è proprio che i test SONO requisiti. Inoltre, sono requisiti eseguibili.
mouviciel,

1
@Bart: I test unitari sono spesso troppo dettagliati per i requisiti (di alto livello) dei clienti, ma l'idea è decisamente valida, soprattutto se consideriamo anche test di livello superiore come i test di accettazione automatizzati che, una volta scritti, dovrebbero essere requisiti definitivi. Questa è l'essenza del "test di accettazione agile".
Martin Wickman,

3
TDD non riguarda i test, riguarda le specifiche. I test costruiti in un approccio TDD sono un mezzo di comunicazione tra sviluppatore e cliente per concordare quale prodotto dovrebbe essere realizzato.
mouviciel,

18

Se si scrive il codice e quindi i test, è fin troppo facile cadere nella trappola della scrittura dei test in modo che il codice passi, piuttosto che scrivere i test per assicurarsi che il codice soddisfi le specifiche.

Detto questo, non è sicuramente l'unico modo per fare le cose, e non esiste un modo "migliore" per sviluppare software. Se dedichi molto lavoro iniziale allo sviluppo di casi di test, non sai se la tua architettura proposta presenta dei difetti fino a molto tempo dopo - mentre se hai sviluppato prima il codice, li incontrerai prima e potrai riprogettarli con meno affondamento sforzo.


Sì, hai ragione sul primo punto, ma mi assicuro sempre di non farlo. Se il test fallisce, vado sempre al codice e mi assicuro che sia corretto, quindi vedo se il mio test è corretto, quindi modifico qualunque sia il problema. Grazie per la tua opinione, lo terrò a mente .. +1 da me per il 1 ° punto e l'ultimo punto ...
k25

2
E se il test passasse? Il test potrebbe passare perché non sta effettivamente esercitando il codice di interesse; questo non può realmente accadere sotto TDD, perché il test inizialmente dovrebbe fallire e, in caso contrario, non si procede al passaggio 2 fino a quando non lo si è risolto. Quindi esiste una modalità di errore nell'ultimo test che non esiste prima nel test.
Carl Manaster,

@Carl Manaster - Sì, hai un punto valido. Dopo aver scritto il codice, sono perfettamente consapevole dei requisiti e quindi il mio caso di test dell'unità sarebbe giusto (idealmente). Se il mio caso di test passa, direi che il codice è corretto, se il test fallisce, seguirò quello che ho detto. Ma, sono d'accordo al 100% che hai un punto valido lì.
k25,

@ k25: il punto è che se il tuo test case passa, non sai ancora se il codice è giusto o meno. Il caso di test potrebbe essere sbagliato.
Anon.

@Anon. - Sì, hai ragione, prenderò in considerazione anche questo caso.
k25,

12

In realtà, le persone restano bloccate dal TDD per i test, anche se dimenticano le altre due lettere nell'acronimo. Qualcosa che può essere letto qui: TDD senza T o TDD non riguarda il Test .

Il fatto è che ho imparato una miriade di altre cose strettamente legate al TDD. Non importa se si esegue prima il test: ciò che conta è pensare alla progettazione del software .

Per poter persino scrivere unit test "nel modo giusto", cioè in modo che siano isolati, rapidi e automatizzati, si spera che ci vorrà un ripensamento su come organizzare il codice in modo che il codice diventi più semplice testare.

Personalmente ho imparato da solo i principi SOLIDI senza sapere che c'era scritto qualcosa del genere. Questo perché la scrittura di unit test mi ha costretto a riscrivere le classi in modo che non diventino troppo complesse da testare. Ha portato a cose come:

  • Ho dovuto spostare la funzionalità, che non aveva senso o risiedeva in metodi privati, in classi separate in modo da poterle testare separatamente. (Principio unico di responsabilità).
  • Ho dovuto evitare grandi strutture ereditarie ed estendere invece le implementazioni con la composizione (prominente nel principio Open-Closed).
  • Dovevo essere furbo riguardo all'eredità, usavo le classi astratte ogni volta che vedevo codice comune che poteva essere condiviso e utilizzavo metodi di stub (principio di sostituzione di Liskov).
  • Ho dovuto scrivere interfacce e classi astratte per poter testare le classi in modo separato. Che ti porta inavvertitamente a scrivere oggetti finti. (Principio di segregazione dell'interfaccia)
  • Poiché ho scritto molte interfacce e classi astratte, ho iniziato a dichiarare variabili e parametri per utilizzare il tipo comune (principio di inversione di dipendenza).

Anche se non eseguo sempre i test prima, mi capita di seguire buoni principi e pratiche OO che inizi a seguire, solo per rendere i test un po 'più facili. Ora non sto scrivendo codice per se stesso. Ho scritto il codice in modo che possa essere facilmente testato o, cosa più importante; facilmente mantenuta .


1
+1 per SOLID ti viene spontaneo quando pensi alla progettazione del software.
ottobre

+1 (in realtà volevo dare +10 ma non posso). Esattamente i miei pensieri - la tua lista di punti era estremamente buona. Questo è uno dei motivi per cui ho posto questa domanda. Ho sentito che le lezioni sono diventate molto di più quando ho iniziato a scrivere i test unitari dopo aver scritto il codice. Ma volevo vedere i vantaggi / gli svantaggi di entrambi i lati, grazie per le tue opinioni!
k25,

10

Tutte le altre risposte sono buone, ma c'è un punto che non è stato toccato. Se si scrive prima il test, si assicura che i test vengano scritti. È allettante, una volta scritto il codice di lavoro, saltare i test e verificarlo tramite l'interfaccia utente. Se hai la disciplina di avere sempre un test fallito prima di scrivere il codice, puoi evitare questa trappola.


4

Se scrivi prima i tuoi test, ti dà un'altra possibilità di pensare al tuo design, prima che quel design sia "gettato nella pietra".

Ad esempio, potresti pensare di aver bisogno di un metodo che accetta un determinato set di parametri. E se prima scrivessi il codice, lo scriveresti in quel modo e faresti in modo che il test si adattasse ai parametri specificati. Ma se scrivi prima il test, potresti pensare "aspetta un minuto, non vorrei usare questo parametro nel codice mainline, quindi forse dovrei cambiare l'API".


+1 per il primo punto. Ma, non arrivando al livello dei parametri, cosa succederebbe se il progetto venisse discusso con altri e accettato?
k25,

@ k25 - se qualcosa è difficile da usare come progettato, ha bisogno di più pensiero. A volte - molto raramente - è solo un compito difficile. Ma più spesso, può essere ridotto a compiti più semplici. Non ho un link, ma Gosling o Goetz hanno fatto un'intervista sulla progettazione delle API qualche anno fa ... vale la pena cercare su Google.
Anon,

certo, grazie per i suggerimenti, cercherò sicuramente di esaminarli ...
k25

2

Dal momento che vedo molti consigli per iniziare a scrivere test e poi passare alla codifica,

C'è davvero una buona ragione per questo.

Se dici "fai ciò che ti sembra giusto", le persone fanno le cose più stupide e pazze.

Se dici "scrivi prima i test", almeno le persone potrebbero provare a fare la cosa giusta.

quali sono gli svantaggi se lo faccio nell'altro modo - scrivi il codice e poi i test unitari?

Di solito, un test scadente e un progetto che deve essere rielaborato per essere testabile.

Tuttavia, questo è solo un "solito". Alcune persone evolvono i progetti e i test in parallelo. Alcune persone mettono in atto codice testabile e scrivono test senza rilavorazioni.

La regola "Prova prima" è specifica per insegnare e istruire le persone che non ne hanno idea.

Allo stesso modo, ci viene sempre detto di guardare "in entrambi i modi" prima di attraversare la strada. Tuttavia, in realtà non lo facciamo. E non importa. Vivo in un paese con guida a destra e ho solo bisogno di guardare a sinistra quando inizio a attraversare.

Quando visito un paese con guida a sinistra, guardare solo a sinistra potrebbe farmi uccidere.

Le regole sono stabilite in modo molto forte per un motivo.

Quello che fai è il tuo problema.


2

il punto di scrivere prima il test è che ti fa pensare

  • come testare il codice
  • l'interfaccia che il codice deve presentare per essere testabile

se stai facendo qualcosa di semplice, probabilmente non importa quale scrivi prima (anche se è bene coltivare l'abitudine test-first) poiché il test sarà semplice e l'interfaccia sarà ovvia

ma TDD passa ai test di accettazione, non solo ai test unitari, e quindi l'interfaccia diventa non banale.


1

Prima di tutto se non scrivi prima i tuoi test, allora non stai facendo Test Driven Development (TDD). I benefici sono numerosi e spesso difficili da credere fino a quando non lo pratichi più volte. Ecco i vantaggi che ho ricevuto facendo TDD rispetto allo sviluppo tradizionale:

  1. Una rete di sicurezza di test: ti consente di apportare grandi cambiamenti senza la paura di rompere inconsapevolmente qualcosa
  2. Design organico: il design con cui finisco è di solito diverso dal design che avrei fatto da zero ed è sempre stato migliore
  3. Produttività: lavorare per piccoli obiettivi (superare questo test) e farlo (tutti i test superano) funziona davvero bene per me e mi mantiene motivato. Aggiungine un paio e la mia produttività raggiunge nuovi massimi.

Libri: Beck, K. Sviluppo guidato dai test con l'esempio

Buon esempio: http://jamesshore.com/Blog/Lets-Play/


+1 - bei punti (specialmente il primo) e grazie per i collegamenti!
k25,

0

Quando scrivi un test, come fai a sapere che rileverà una condizione di errore? La risposta è "prova il test". Il modo in cui lo fai è scrivere prima il test, vederlo fallire e vederlo passare solo quando l'unità sotto test è stata codificata correttamente (il ciclo rosso / verde / refactor menzionato in una delle altre risposte).

Scrivendo prima il codice e poi il test lascia aperta la questione se il test mostrerebbe un fallimento onesto.

Ricorda che i tuoi test esprimono specifiche. Se devi rivedere i tuoi test man mano che il tuo codice "prende forma", suggerisce che le tue specifiche stanno cambiando. Potrebbe essere o meno una buona cosa. Potrebbe significare che la tua comprensione del problema inizialmente non era corretta. D'altra parte, potrebbe significare che stai testando "come" l'unità sta facendo il suo lavoro piuttosto che ciò che si suppone stia realizzando.

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.