È una buona idea scrivere tutti i possibili casi di test dopo aver trasformato il team in TDD per ottenere una copertura completa?


17

Supponiamo di avere una grande applicazione a livello aziendale senza test unitari / funzionali. Non vi è stato alcun processo di sviluppo guidato dai test durante lo sviluppo a causa di scadenze molto strette (so che non dovremmo mai promettere scadenze strette quando non siamo sicuri, ma ciò che è fatto è fatto!)

Ora che tutte le scadenze sono passate e le cose sono calme, tutti hanno deciso di trasformarci in un team produttivo basato su TDD / BDD ... Yay!

Ora la domanda riguarda il codice che abbiamo già: (1) È ancora ok o buona idea fermare la maggior parte dello sviluppo e iniziare a scrivere interi casi di test dall'inizio, anche se tutto funziona perfettamente OK (ancora!) ? Oppure (2) è meglio aspettare che accada qualcosa di brutto e poi durante la correzione scrivere nuovi test unitari, oppure (3) persino dimenticare i codici precedenti e scrivere solo test unitari per i nuovi codici e rimandare tutto al prossimo refactor principale.

Ci sono alcuni articoli validi e correlati come questo . Non sono ancora sicuro se valga la pena investire in questo, considerando che abbiamo un tempo molto limitato e molti altri progetti / lavori ci stanno aspettando.

Nota : questa domanda spiega / immagina una situazione totalmente imbarazzante in un team di sviluppo. Non si tratta di me o di nessuno dei miei colleghi; è solo una situazione immaginaria. Potresti pensare che ciò non dovrebbe mai accadere o il responsabile dello sviluppo è responsabile di un tale casino! Ma comunque, ciò che è fatto è fatto. Se possibile, per favore non sottovalutare solo perché pensi che questo non dovrebbe mai accadere.



6
Probabilmente dovresti prepararti per le prossime scadenze e non ti sarà più permesso di fare TDD. Forse dicendo a chiunque abbia guidato l'ultimo round di assorbimento del debito tecnico perché non è stata una grande idea.
jonrsharpe,

1
@gnat Penso che non sia una domanda duplicata. Il team menzionato non ha alcun tipo di test (nemmeno test di integrazione)
Michel Gokan,

1
@gnat la domanda è: cosa accadrà ai nostri nuovi test unitari? Potrebbero sembrare incompleti o addirittura inutili senza scrivere tutti i test unitari per i codici precedentemente scritti. La domanda che lei menziona non copre questa specifica preoccupazione.
Michel Gokan,

1
Non è possibile scrivere tutti i possibili casi di test. È utile solo scrivere tutti i casi di test che ti interessano. Ad esempio, se hai bisogno di una funzione che accetti un intvalore e restituisca qualcosa di specifico, non è possibile scrivere un unit test per ogni possibile intvalore, ma probabilmente ha senso testare una manciata di valori utili che potrebbero inciampare nel codice, come numeri negativi (incluso minint), zero maxint, ecc. per assicurarsi che alcuni casi limite siano coperti.
Christopher Schultz,

Risposte:


36

Non vi è stato alcun processo di sviluppo guidato dai test durante lo sviluppo a causa di scadenze molto strette

Questa affermazione è molto preoccupante. Non perché significa che hai sviluppato senza TDD o perché non stai testando tutto. Questo è preoccupante, perché dimostra che TDD ti rallenterà e ti farà perdere una scadenza.

Finché lo vedi in questo modo non sei pronto per il TDD. TDD non è qualcosa in cui puoi gradualmente addentrarti. O sai come farlo oppure no. Se provi a farlo a metà strada, lo farai e sembrerai brutto.

TDD è qualcosa che dovresti prima praticare a casa. Impara a farlo, perché ti aiuta a programmare ora . Non perché qualcuno ti abbia detto di farlo. Non perché sarà di aiuto quando si apportano modifiche in un secondo momento. Quando diventa qualcosa che fai perché sei di fretta, allora sei pronto a farlo professionalmente.

TDD è qualcosa che puoi fare in qualsiasi negozio. Non è nemmeno necessario inserire il codice di prova. Puoi tenerlo per te se gli altri disprezzano i test. Quando lo fai bene, i test accelerano il tuo sviluppo anche se nessun altro li esegue.

D'altra parte, se gli altri adorano ed eseguono i test, è necessario tenere presente che anche in un negozio TDD non è il tuo compito controllare i test. Serve per creare un codice di produzione funzionante collaudato. Se sembra essere testabile, pulito.

Se pensi che il management debba credere in TDD o che i tuoi colleghi programmatori debbano supportare i tuoi test, allora stai ignorando la cosa migliore che TDD fa per te. Ti mostra rapidamente la differenza tra ciò che pensi che faccia il tuo codice e ciò che effettivamente fa.

Se non riesci a vedere come questo, da solo, può aiutarti a rispettare una scadenza più velocemente, allora non sei pronto per TDD al lavoro. Devi esercitarti a casa.

Detto questo, è bello quando il team può utilizzare i test per aiutarli a leggere il codice di produzione e quando la direzione acquisterà nuovi strumenti TDD.

È una buona idea scrivere tutti i possibili casi di test dopo aver trasformato il team in TDD?

Indipendentemente da ciò che il team sta facendo, non è sempre una buona idea scrivere tutti i possibili casi di test. Scrivi i casi di test più utili. La copertura del codice al 100% ha un costo. Non ignorare la legge dei rendimenti decrescenti solo perché è difficile fare una sentenza.

Risparmia la tua energia di test per la logica di business interessante. Il materiale che prende le decisioni e applica la politica. Metti alla prova questo. Il noioso codice di colla strutturale di facile lettura che collega semplicemente le cose insieme non ha bisogno di essere testato altrettanto male.

(1) È ancora ok o buona idea fermare la maggior parte dello sviluppo e iniziare a scrivere interi casi di test dall'inizio, anche se tutto funziona perfettamente OK (ancora!)? O

No. Questo è il pensiero "facciamo una riscrittura completa". Questo distrugge la conoscenza conquistata duramente. Non chiedere alla direzione il tempo di scrivere i test. Scrivi i test. Una volta che sai cosa stai facendo, i test non ti rallenteranno.

(2) è meglio aspettare che accada qualcosa di brutto e poi durante la correzione scrivere nuovi test unitari, oppure

(3) dimentica persino i codici precedenti e scrivi solo i test unitari per i nuovi codici e rimanda tutto al prossimo refactor principale.

Risponderò 2 e 3 allo stesso modo. Quando modifichi il codice, per qualsiasi motivo, è davvero bello se riesci a scivolare in un test. Se il codice è legacy, al momento non è gradito un test. Ciò significa che è difficile testarlo prima di cambiarlo. Bene, dal momento che lo stai cambiando comunque puoi cambiarlo in qualcosa di testabile e testarlo.

Questa è l'opzione nucleare. È rischioso. Stai apportando modifiche senza test. Ci sono alcuni trucchi creativi per mettere alla prova il codice legacy prima di modificarlo. Cerchi le cosiddette cuciture che ti consentono di cambiare il comportamento del tuo codice senza cambiare il codice. Si modificano i file di configurazione, si creano file, qualunque cosa serva.

Michael Feathers ci ha dato un libro su questo: lavorare in modo efficace con il codice legacy . Dagli una lettura e vedrai che non devi bruciare tutto ciò che è vecchio per creare qualcosa di nuovo.


37
"I test accelerano il tuo sviluppo anche se nessun altro li esegue." - Trovo che questo sia palesemente falso. Questo non è sicuramente il luogo per iniziare una discussione al riguardo, ma i lettori dovrebbero tenere presente che il punto di vista presentato qui non è unanime.
Martin Ba,

4
In realtà spesso i test aumentano il tuo sviluppo a lungo termine e affinché TDD sia davvero efficiente, tutti devono crederci, altrimenti spenderesti metà del tuo team a riparare i test interrotti da altri.
hspandher,

13
"pensi che TDD ti rallenterà e ti farà perdere una scadenza." Penso che probabilmente sia così. Nessuno usa TDD perché si aspettano che la prima scadenza venga rispettata più rapidamente. Il vero vantaggio (almeno secondo la mia stima) sono i dividendi in corso che testeranno il gioco in futuro, per catturare le regressioni e per rafforzare la fiducia nella sperimentazione sicura. Penso che questo vantaggio superi i costi iniziali per la scrittura dei test, la maggior parte probabilmente sarebbe d'accordo, ma se devi rispettare la scadenza ravvicinata, non hai davvero scelta.
Alexander - Ripristina Monica il

1
Lo trovo analogo all'acquisto di una casa. Se avessi la somma forfettaria per pagare una casa, risparmierai molto sugli interessi e sarebbe a lungo andare fantastico. Ma se hai bisogno di una casa immediatamente ... allora sei costretto ad adottare un approccio a breve termine che non è ottimale a lungo termine
Alexander - Ripristina Monica il

3
TDD = can = aumenta le prestazioni se i test e il codice sono sviluppati in parallelo, mentre la funzionalità è fresca nella mente dello sviluppatore. Le recensioni del codice ti diranno se un altro essere umano pensa che il codice sia corretto. I casi di test ti diranno se la specifica, come incorporata in un caso di test, viene implementata. Altrimenti, sì, TDD può essere una seccatura soprattutto se non ci sono specifiche funzionali e lo scrittore di test sta facendo anche il reverse engineering.
Julie ad Austin, il

22

Va ancora bene o è una buona idea interrompere gran parte dello sviluppo e iniziare a scrivere interi casi di test dall'inizio [...]?

Dato il codice legacy 1 , scrivere unit test in queste situazioni:

  • durante la correzione di bug
  • durante il refactoring
  • quando si aggiungono nuove funzionalità al codice esistente

Utile come i test unitari, la creazione di una suite completa di test unitari per una base di codice 1 esistente probabilmente non è un'idea realistica. I poteri che ti hanno spinto a consegnare in tempi stretti. Non ti hanno dato il tempo di creare test unitari adeguati mentre stavi sviluppando. Pensi che ti daranno il tempo necessario per creare test per il "programma che funziona"?

1 Il codice legacy è il codice senza unit test. Questa è la definizione TDD di codice legacy. Si applica anche se il codice legacy viene consegnato di recente [anche se l'inchiostro non si è ancora asciugato].


Ma poi i nostri nuovi test unitari per nuove funzionalità possono sembrare incompleti o addirittura inutili senza perdere test unitari. No?
Michel Gokan,

7
(1) Senza valore? Certamente no. Per lo meno, testano la nuova funzionalità. La prossima volta che qualcuno vorrà modificare questa funzione, riutilizzerà gran parte dei test esistenti. (2) incompleto? Forse sì forse no. Se si creano anche unit test che testano la funzionalità legacy da cui dipende la nuova funzionalità, i test potrebbero essere abbastanza completi per scopi pratici. In altre parole, creare test unitari aggiuntivi che penetrano nella funzionalità legacy. Penetrare a che profondità? Dipende dall'architettura del programma, dalle risorse disponibili, dal supporto istituzionale.
Nick Alexeev,

L'aspetto negativo di "scrivere test quando inciampi nel bisogno di loro" è che c'è un rischio maggiore di finire con un patchwork di test scritti da sviluppatori diversi con idee diverse. Non sto dicendo che questa risposta sia sbagliata, ma richiede una mano ferma che mantenga uniforme la qualità e lo stile dei test.
Flater,

4
L'uniformità di @Flater offre un falso comfort. Voglio test che rendono il codice di produzione di facile lettura. Non test che sembrano tutti uguali. Ti perdonerò mescolando quadri di prova completamente diversi se renderà più facile capire cosa fa il codice di produzione.
candied_orange,

2
@Flater Non ho affermato il brutto codice di produzione. Affermo che il punto dei test è rendere leggibile il codice di produzione. Accetterò volentieri una folla eclettica di test che rendono più semplice la lettura del codice di produzione. Fai attenzione a rendere l'uniformità un obiettivo in sé. La leggibilità è re.
candied_orange,

12

Nella mia esperienza, i test non hanno bisogno di una copertura totale per essere utili. Invece, inizi a raccogliere diversi tipi di benefici all'aumentare della copertura:

  • copertura superiore al 30% (ovvero un paio di test di integrazione): se i tuoi test falliscono, qualcosa è estremamente rotto (o i tuoi test falliscono). Per fortuna i test ti hanno avvisato rapidamente! Ma le versioni richiederanno comunque numerosi test manuali.
  • copertura superiore al 90% (ovvero la maggior parte dei componenti ha test unitari superficiali): se i test vengono superati, è probabile che il software vada bene per lo più. Le parti non testate sono casi limite, il che va bene per i software non critici. Ma le versioni richiederanno comunque alcuni test manuali.
  • altissima copertura di funzioni / dichiarazioni / rami / requisiti: stai vivendo il sogno di TDD / BDD , e i tuoi test riflettono con precisione la funzionalità del tuo software. È possibile eseguire il refactoring con elevata sicurezza, compresi i cambiamenti architetturali su larga scala. Se i test hanno esito positivo, il software è quasi pronto per il rilascio; sono richiesti solo alcuni test manuali del fumo.

La verità è che se non inizi con BDD non ci arriverai mai, perché il lavoro richiesto per testare dopo la codifica è semplicemente eccessivo. Il problema non è scrivere i test, ma soprattutto conoscere i requisiti effettivi (anziché i dettagli sull'implementazione accidentale) e saper progettare il software in modo funzionale e facile da testare. Quando scrivi i test prima o insieme al codice, questo è praticamente gratuito.

Poiché le nuove funzionalità richiedono test, ma i test richiedono modifiche di progettazione, ma anche il refactoring richiede test, hai un po 'di problemi con pollo e uova. Mentre il tuo software si avvicina a una copertura decente, dovrai fare un attento refactoring in quelle parti del codice in cui si verificano nuove funzionalità, solo per rendere le nuove funzionalità testabili. Questo ti rallenterà molto, inizialmente. Ma rifattorizzando e testando solo le parti in cui è necessario un nuovo sviluppo, i test si concentrano anche sull'area in cui sono maggiormente necessari. Il codice stabile può continuare senza test: se fosse difettoso, dovresti comunque modificarlo.

Mentre provi ad adattarti a TDD, una metrica migliore della copertura totale del progetto sarebbe la copertura del test nelle parti che vengono modificate. Questa copertura dovrebbe essere molto elevata sin dall'inizio, sebbene non sia possibile testare tutte le parti del codice che sono interessate da un refactoring. Inoltre, ottieni la maggior parte dei vantaggi dell'alta copertura dei test all'interno dei componenti testati. Non è perfetto, ma è ancora abbastanza buono.

Si noti che mentre i test unitari sembrano essere comuni, iniziare con i pezzi più piccoli non è una strategia adatta per testare un software legacy. Ti consigliamo di iniziare con i test di integrazione che esercitano contemporaneamente una grande parte del software.

Ad esempio, ho trovato utile estrarre i casi di test di integrazione dai file di registro reali. Ovviamente l'esecuzione di tali test può richiedere molto tempo, motivo per cui potresti voler configurare un server automatizzato che esegua i test regolarmente (ad esempio un server Jenkins attivato da commit). Il costo di installazione e manutenzione di un server di questo tipo è molto ridotto rispetto al non eseguire regolarmente i test, a condizione che eventuali errori di test vengano effettivamente corretti rapidamente.


"Oltre il 90% di copertura (ovvero la maggior parte dei componenti ha test unitari superficiali): se i test vengono superati, il software è probabilmente in gran parte a posto. Le parti non testate sono casi limite, il che va bene per i software non critici ." A me sembra un po 'strano, FWIW, preferirei avere una copertura del 30% costituita principalmente da casi limite piuttosto che una copertura del 90% consistente interamente nel comportamento del percorso previsto (cosa facile da fare per i tester manuali); Consiglio di pensare "fuori dagli schemi" quando si scrivono test e si basano su casi di test (insoliti) scoperti manualmente ogni volta che è possibile.
giovedì

5

Non scrivere test per codice esistente. Non ne vale la pena.

Quello che hai fatto è già stato in qualche modo testato in modo completamente informale: l'hai provato a mano costantemente, le persone hanno fatto alcuni test non automatizzati, ora vengono utilizzati. Ciò significa che non troverai molti bug .

Ciò che rimane sono i bug a cui non hai pensato. Ma quelli sono esattamente quelli per cui non penserai di scrivere test unitari, quindi probabilmente non li troverai ancora.

Inoltre, un motivo per TDD è farti pensare a quali sono i requisiti esatti di un po 'di codice prima di scriverlo. In qualunque modo diverso, l'hai già fatto.

Nel frattempo, è ancora tanto lavoro per scrivere questi test quanto sarebbe stato scriverli in anticipo. Costerà molto tempo, per pochi benefici.

Ed è estremamente noioso scrivere un sacco di test senza codifica e trovare quasi nessun bug. Se inizi a farlo, le persone nuove a TDD lo odieranno .

In breve, gli sviluppatori lo odieranno e i manager lo vedranno come costoso, mentre non vengono trovati molti bug. Non arriverai mai alla parte TDD effettiva.

Usalo su cose che vuoi cambiare, come una normale parte del processo.


1
Non sono assolutamente d'accordo con "Non scrivere test per il codice esistente. Non ne vale la pena." Se il codice funziona in modo ragionevole, i test possono essere l'unica specifica esistente. E se il codice è in manutenzione, l'aggiunta di test è l'unico modo per garantire che le funzioni che funzionano non vengano interrotte da modifiche apparentemente non correlate.
Julie ad Austin, il

3
@JulieinAustin: D'altra parte, senza una specifica, non sai esattamente cosa dovrebbe fare il codice. E se non sai già cosa dovrebbe fare il codice, potresti benissimo scrivere test inutili - o peggio, fuorvianti che modificano sottilmente le specifiche - e ora diventa richiesto un comportamento accidentale e / o sbagliato.
cHao,

2

Un test è un mezzo per comunicare la comprensione.

Pertanto, scrivere solo i test per ciò che si capisce dovrebbe essere vero.

Puoi capire cosa dovrebbe essere vero solo quando ci lavori.

Pertanto scrivi solo i test per il codice con cui stai lavorando.

Quando lavorerai con il codice imparerai.

Pertanto, scrivere e riscrivere i test per acquisire ciò che hai appreso.

Risciacqua e ripeti.

Avere uno strumento di copertura del codice eseguito con i test e accettare solo commit sulla linea principale che non riducono la copertura. Alla fine raggiungerai un alto livello di copertura.

Se non si lavora con il codice da un po 'di tempo, è necessario prendere una decisione aziendale. Ora è molto probabilmente così ereditato che nessuno nella tua squadra sa come lavorarci. Probabilmente ha librerie / compilatori / documentazione non aggiornati che è una responsabilità enorme in quasi tutti i modi.

Due opzioni:

  1. Investi il ​​tempo per leggerlo, imparare da esso, scrivere test per esso e riformattarlo. Piccoli gruppi di modifiche con rilasci frequenti.
  2. Trova un modo per abbandonare quel software. Non è possibile modificarlo se richiesto comunque.

0

(1) È ancora ok o buona idea fermare la maggior parte dello sviluppo e iniziare a scrivere interi casi di test dall'inizio, anche se tutto funziona perfettamente OK (ancora!)?
(2) è meglio aspettare che accada qualcosa di brutto e poi durante la correzione scrivere nuovi test unitari

Uno degli scopi principali dei test è garantire che una modifica non abbia interrotto nulla. Questo è un processo in tre fasi:

  1. Conferma che i test hanno esito positivo
  2. Farti delle modifiche
  3. Conferma che i test hanno ancora esito positivo

Questo significa che devi avere dei test di lavoro prima di cambiare qualcosa. Se scegli il secondo percorso, ciò significa che dovrai costringere i tuoi sviluppatori a scrivere test prima ancora che tocchino il codice. E sospetto fortemente che di fronte a un cambiamento nel mondo reale, gli sviluppatori non daranno alle unit test l'attenzione che meritano.

Quindi suggerisco di dividere le attività di scrittura di test e di modifica per evitare che gli sviluppatori sacrificino la qualità dell'una per l'altra.

anche se tutto funziona completamente bene (ancora!)?

Giusto per sottolinearlo in modo specifico, è un'idea sbagliata comune che sono necessari test solo quando il codice non funziona. Hai bisogno di test anche quando il codice funziona, ad esempio per dimostrare a qualcuno che [bug che si verificano di recente] non è dovuto alla tua parte perché i test stanno ancora superando.
Confermare che tutto funziona ancora come prima era un importante vantaggio del test che stai omettendo quando sottintendi che non hai bisogno di test quando il codice funziona.

(3) dimentica persino i codici precedenti e scrivi solo i test unitari per i nuovi codici e rimanda tutto al prossimo refactor principale

Idealmente, tutto il codice sorgente esistente dovrebbe ora ottenere unit test. Tuttavia, vi è una ragionevole argomentazione secondo cui il tempo e gli sforzi (e i costi) necessari per farlo non sono semplicemente rilevanti per alcuni progetti.
Ad esempio, un'applicazione che non è più in fase di sviluppo e non dovrebbe più essere modificata (ad es. Il client non la utilizza più o il client non è più un client), si può sostenere che non è più rilevante testare questo codice .

Tuttavia, non è così chiaro dove si disegna la linea. Questo è qualcosa che un'azienda deve considerare in un'analisi costi-benefici. Scrivere test costa tempo e fatica, ma si aspettano sviluppi futuri su quell'applicazione? I guadagni derivanti dal test unitario superano i costi della loro scrittura?

Questa non è una decisione che tu (come sviluppatore) puoi prendere. Nella migliore delle ipotesi, è possibile offrire una stima del tempo necessario per implementare i test su un determinato progetto e spetta alla direzione decidere se vi è un'aspettativa sufficiente di dover effettivamente mantenere / sviluppare il progetto.

e rimandare tutto al prossimo grande refattore

Se il prossimo refactor principale è un dato, allora devi davvero scrivere i test.

Ma non rimandare fino a quando non si affrontano cambiamenti importanti. Il mio punto iniziale (non combinare la scrittura di test e l'aggiornamento del codice) è ancora valido, ma voglio aggiungere un secondo punto qui: i tuoi sviluppatori attualmente conoscono il loro modo di aggirare il progetto meglio di quanto faranno in sei mesi se trascorrono quel tempo a lavorare su altri progetti. Sfrutta i periodi di tempo in cui gli sviluppatori sono già riscaldati e non hanno bisogno di capire come le cose funzioneranno di nuovo in futuro.


0

I miei due centesimi:

Attendi un importante aggiornamento tecnico del sistema e scrivi i test poi ... ufficialmente con il supporto dell'azienda.

In alternativa, supponiamo che tu sia un negozio SCRUM, il tuo carico di lavoro è rappresentato dalla capacità e puoi assegnarne una percentuale ai test unitari, ma ...

Dire che tornerai indietro e scrivere i test è ingenuo, quello che farai davvero è scrivere test, refactor e scrivere altri test dopo che il refactor ha reso il codice più testabile, motivo per cui è meglio iniziare con test come già sapete e ...

È meglio per l'autore originale scrivere test e refactoring del codice che hanno scritto in precedenza, non è l'ideale, ma per esperienza si desidera che il refactor migliori il peggio del 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.