C'è qualcosa come avere troppi test unitari?


139

Mi è stato assegnato il compito di scrivere unit test per un'applicazione esistente. Dopo aver finito il mio primo file, ho 717 righe di codice di prova per 419 righe di codice originale.

Questo rapporto diventerà ingestibile man mano che aumentiamo la copertura del nostro codice?

La mia comprensione del test unitario era di testare ogni metodo della classe per garantire che ogni metodo funzionasse come previsto. Tuttavia, nella richiesta pull il mio responsabile tecnico ha notato che avrei dovuto concentrarmi su test di livello superiore. Ha suggerito di testare 4-5 casi d'uso che sono più comunemente usati con la classe in questione, piuttosto che testare esaurientemente ciascuna funzione.

Mi fido del commento del mio capo tecnico. Ha più esperienza di me e ha un istinto migliore nella progettazione di software. Ma come fa un team composto da più persone a scrivere test per uno standard così ambiguo; cioè, come faccio a conoscere i miei colleghi e condivido la stessa idea per "casi d'uso più comuni"?

Per me, la copertura del test unitario al 100% è un obiettivo elevato, ma anche se avessimo raggiunto solo il 50%, sapremmo che il 100% di quel 50% era coperto. Altrimenti, scrivere test per parte di ogni file lascia molto spazio a barare.


145
Dipende. Stai scrivendo un gioco di tic-tac-toe o stai scrivendo un codice per gestire un reattore nucleare?
Bryan Oakley,

11
Con un numero sufficiente di test unitari, è possibile rilevare problemi di implementazione hardware esotici come il bug Pentium FDIV o le correlazioni nelle primitive crittografiche, quindi sembra che non ci sia un limite rigido che nessun ulteriore test unitario potrebbe essere utile. Solo un limite pratico su quando è troppo costoso.
Nat

5
I test ai livelli più alti ti forniranno una migliore prospettiva della copertura reale. Per copertura reale intendo che è più probabile che accada durante il normale utilizzo del sistema. Questo è il tipo di copertura che vuoi ottenere prima. Nel 50% che l'ultimo a raggiungere potrebbe avere YAGNI o codice morto che una volta rimosso contribuirà ad aumentare anche la copertura complessiva.
Laiv

5
Se ricevi troppi test (che al momento non sembra avere) il problema più probabile è che il codice che stai testando fa troppo. Quindi la singola responsabilità non viene rispettata. Quando il codice è ben suddiviso, anche i test non creano molti oneri. Se le lezioni fanno molto, hanno molti effetti collaterali, ecc. Diventerà un incubo.
Luc Franken,

12
Il documento di test di sqlite è una lettura divertente: sqlite.org/testing.html . Citazione: "la libreria SQLite è composta da circa 122,9 KSLOC di codice C. Al confronto, il progetto ha 745 volte più codice di test e script di test - 91596.1 KSLOC."
user60561,

Risposte:


180

Sì, con una copertura del 100% scriverai alcuni test che non ti servono. Sfortunatamente, l'unico modo affidabile per determinare quali test non sono necessari è di scriverli tutti, quindi attendere circa 10 anni per vedere quali non hanno mai fallito.

Mantenere molti test non è di solito problematico. Molti team hanno integrato i test di integrazione e di sistema oltre al 100% di copertura dei test unitari.

Tuttavia, non ti trovi in ​​una fase di manutenzione di prova, stai giocando al passo. È molto meglio avere il 100% delle lezioni con il 50% di copertura del test rispetto al 50% delle lezioni con il 100% di copertura del test, e il tuo lead sembra cercare di farti assegnare il tuo tempo di conseguenza. Dopo aver stabilito questa linea di base, il passaggio successivo è in genere il 100% dei file che vengono modificati in futuro.


11
Grazie per la tua risposta. Mi ha aiutato a mettere la mia domanda in prospettiva e ha affrontato il vero problema: il mio atteggiamento! +1
user2954463

43
@astra Il tuo atteggiamento non è poi così male. È bello chiedersi perché. Per rispondere alla tua altra domanda, eccellente domanda: "Come faccio a sapere i miei colleghi e condivido la stessa idea per" casi d'uso più comuni "? Li fai guardare ai tuoi test. Guarda i loro. Parlane. Imparerai molto e forse lo faranno anche loro. I test di revisione del codice raramente sono una perdita di tempo. Anche se tendo a fare i miei in un terminal piuttosto che in una sala conferenze
candied_orange

18
Un test che non ha mai fallito in 10 anni non garantisce nemmeno che sia inutile, potrebbe finire per fallire nell'anno 11.
Pharap

24
Pragmaticamente, potresti adottare l'approccio opposto. Scrivi i test che ritieni coprano i casi comuni. Ma poi, ogni volta che si verifica un errore, scrivere un test per coprire quell'area.
stannius

10
@Pharap Il mio unico problema con questa risposta è che c'è il presupposto implicito che un test può aggiungere valore solo quando fallisce. Un buon test unitario fornisce anche un'ottima forma di documentazione vivente. Ha anche aggiunto valore quando hai scritto il test, costringendoti a pensare a riusabilità / compostabilità / incapacità. Il codice non testato nella mia esperienza tende ad essere bestie monolitiche inflessibili.
Art

66

Se hai lavorato su basi di codice di grandi dimensioni create utilizzando Test Driven Development, sapresti già che ci possono essere troppi test unitari. In alcuni casi, la maggior parte dello sforzo di sviluppo consiste nell'aggiornamento di test di bassa qualità che sarebbero meglio implementati come controlli invarianti, precondizione e postcondizione nelle classi pertinenti, in fase di esecuzione (ovvero test come effetto collaterale di un test di livello superiore ).

Un altro problema è la creazione di progetti di scarsa qualità, che utilizzano tecniche di progettazione guidate dal carico, che si traducono in una proliferazione di cose da testare (più classi, interfacce, ecc.). In questo caso l'onere potrebbe sembrare l'aggiornamento del codice di test, ma il vero problema è la progettazione di scarsa qualità.


16
È stato votato come unit test per la valutazione di pre-condizioni, post-condizioni e invarianti. In questo modo ogni uso è un test unitario quando quel codice di debug è attivo.
Persixty,

Questa è un'ottima risposta e si allinea perfettamente alla mia esperienza.
Tony Ennis,

E un altro problema: se hai check-in recintati (dovresti davvero!) Con grandi quantità di bassa qualità, probabilmente anche i test a lungo termine rallenteranno tutto senza fornire vantaggi reali. E poi ovviamente il fatto divertente in cui cambi una cosa in una classe e centinaia di test falliscono.
Voo,

3
Questa è una risposta molto migliore di quella accettata! "In alcuni casi, la maggior parte dello sforzo di sviluppo consiste nell'aggiornamento di test di bassa qualità" - L'ho sperimentato e fa schifo. Più che non avere alcun test, per certi aspetti.
Benjamin Hodgson,

36

Risposte alle tue domande

C'è qualcosa come avere troppi test unitari?

Certo ... Potresti, ad esempio, avere più test che sembrano essere diversi a prima vista ma testare davvero la stessa cosa (logicamente dipendono dalle stesse linee di "interessante" codice dell'applicazione sotto test).

Oppure potresti testare gli interni del tuo codice che non emergono mai verso l'esterno (ovvero, non fanno parte di alcun tipo di contratto di interfaccia), dove si potrebbe discutere se ciò abbia un senso, a tutti. Ad esempio la formulazione esatta dei messaggi di registro interni o altro.

Mi è stato assegnato il compito di scrivere unit test per un'applicazione esistente. Dopo aver finito il mio primo file, ho 717 righe di codice di prova per 419 righe di codice originale.

Questo mi sembra abbastanza normale. I test impiegano molte righe di codice per l'installazione e lo smontaggio oltre ai test effettivi. Il rapporto può migliorare o no. Io stesso sono abbastanza pesante, e spesso investo più tempo e tempo sui test rispetto al codice reale.

Questo rapporto diventerà ingestibile man mano che aumentiamo la copertura del nostro codice?

Il rapporto non tiene conto di così tanto. Esistono altre qualità di test che tendono a renderle ingestibili. Se devi regolarmente refactoring di un sacco di test quando esegui modifiche piuttosto semplici nel tuo codice, dovresti dare una buona occhiata ai motivi. E quelli non sono quante linee hai, ma come ti avvicini alla codifica dei test.

La mia comprensione del test unitario era di testare ogni metodo della classe per garantire che ogni metodo funzionasse come previsto.

Ciò è corretto per i test "unitari" in senso stretto. Qui, "unità" è qualcosa come un metodo o una classe. Il punto del test "unit" è testare solo una specifica unità di codice, non l'intero sistema. Idealmente, dovresti rimuovere tutto il resto del sistema (usando double o quant'altro).

Tuttavia, nella richiesta pull il mio responsabile tecnico ha notato che avrei dovuto concentrarmi su test di livello superiore.

Quindi sei caduto nella trappola dell'ipotesi che le persone intendessero effettivamente test unitari quando dicevano test unitari. Ho incontrato molti programmatori che dicono "unit test" ma significano qualcosa di completamente diverso.

Ha suggerito di testare 4-5 casi d'uso che sono più comunemente usati con la classe in questione, piuttosto che testare esaurientemente ciascuna funzione.

Certo, concentrarsi solo sull'80% dei codici importanti riduce anche il carico ... Apprezzo il fatto che tu pensi molto al tuo capo, ma questo non mi sembra la scelta ottimale.

Per me, la copertura del test unitario al 100% è un obiettivo elevato, ma anche se avessimo raggiunto solo il 50%, sapremmo che il 100% di quel 50% era coperto.

Non so cosa sia la "copertura unit test". Suppongo che intendi "copertura del codice", ovvero che dopo aver eseguito la suite di test, ogni riga di codice (= 100%) è stata eseguita almeno una volta.

Questa è una buona metrica del campo da baseball, ma di gran lunga non è il migliore standard per cui si possa puntare. L'esecuzione delle righe di codice non è il quadro completo; questo non tiene conto di percorsi diversi attraverso rami complicati e nidificati, per esempio. È più una metrica che punta il dito su pezzi di codice che sono testati troppo poco (ovviamente, se una classe ha una copertura del codice del 10% o del 5%, allora qualcosa non va); d'altra parte una copertura del 100% non ti dirà se hai effettuato test sufficienti o se hai eseguito correttamente i test.

Test d'integrazione

Mi irrita sostanzialmente quando le persone parlano costantemente di unit test oggi, per impostazione predefinita. Secondo me (ed esperienza), il test unitario è ottimo per le librerie / API; in più aree orientate al business (di cui parliamo di casi d'uso come nella domanda in corso), non sono necessariamente l'opzione migliore.

Per il codice generale dell'applicazione e nel business medio (dove guadagnare denaro, rispettare scadenze e soddisfare la soddisfazione del cliente è importante e si desidera principalmente evitare bug che sono direttamente in faccia all'utente o che potrebbero portare a disastri reali - non lo siamo parlando del lancio di missili della NASA qui), l'integrazione o i test di funzionalità sono molto più utili.

Quelli vanno di pari passo con lo sviluppo guidato dal comportamento o lo sviluppo guidato dalle caratteristiche; quelli non funzionano con (severi) test unitari, per definizione.

Per farla breve (ish), un test di integrazione / funzionalità esercita l'intero stack dell'applicazione. In un'applicazione basata sul web, si comporterebbe come un browser che fa clic sull'applicazione (e no, ovviamente non deve essere così semplicistico, ci sono framework molto potenti là fuori per farlo - controlla http: // cucumber. io per un esempio).

Oh, per rispondere alle tue ultime domande: fai in modo che tutto il tuo team abbia un'elevata copertura dei test assicurandoti che una nuova funzione sia programmata solo dopo che il suo test è stato implementato e fallito. E sì, questo significa ogni caratteristica. Questo ti garantisce una copertura delle funzioni al 100% (positiva). Per definizione garantisce che una funzione dell'applicazione non "andrà mai via". Non garantisce una copertura del codice del 100% (ad esempio, a meno che non si programmino attivamente funzioni negative, non si eserciterà la gestione degli errori / gestione delle eccezioni).

Non ti garantisce un'applicazione senza bug; ovviamente vorrai scrivere test di funzionalità per situazioni buggy ovvie o molto pericolose, input dell'utente errato, hacking (ad esempio, gestione della sessione circostante, sicurezza e simili) ecc .; ma anche solo programmare i test positivi ha un enorme vantaggio ed è abbastanza fattibile con quadri moderni e potenti.

I test di funzionalità / integrazione ovviamente hanno una loro lattina di worm (ad esempio, prestazioni; test ridondanti di framework di terze parti; poiché di solito non usi i doppi, tendono anche a essere più difficili da scrivere, nella mia esperienza ...), ma io ' d prendere un'applicazione testata con funzionalità positive al 100% su un'applicazione testata con copertura del codice al 100% (non libreria!) ogni giorno.


1
I test di integrazione sono ottimi, ma non sostituiscono i test unitari, anche non per le applicazioni aziendali. Esistono diversi problemi: a) per definizione richiedono molto tempo per essere eseguiti (significa anche che i test incrementali sono praticamente inutili), b) rendono incredibilmente difficile individuare il problema reale (oh 50 test di integrazione non sono riusciti, quale cambiamento ha causato questo?) ec) coprono ripetutamente gli stessi percorsi di codice.
Voo,

1
a) è un problema perché rende i test sui check-in chiusi ingombranti e rende meno probabile che i programmatori eseguano i test ripetutamente durante lo sviluppo, che accoppiato con b) diminuisce l'efficienza e la capacità di diagnosticare rapidamente i bug. c) significa che cambiare una piccola cosa può facilmente far fallire dozzine o centinaia di test di integrazione, il che significa che passerai un sacco di tempo a risolverli. Questo significa anche che i test di integrazione testano principalmente solo percorsi felici, perché scrivere questi test come target è ingombrante o impossibile.
Voo,

1
@Voo, tutto ciò che hai scritto è vero, e per quanto posso dire ho già menzionato tutti i problemi che hai notato nella risposta ...
AnoE

Se sei d'accordo con quel riassunto, non vedo davvero come puoi giungere alla conclusione che preferiresti i test di integrazione ai test unitari. Le suite complete di test di integrazione di programmi di grandi dimensioni richiedono ore o addirittura giorni per essere eseguite, sono ottime da avere ma quasi inutili durante lo sviluppo reale. E i tuoi test di accettazione (cosa che tutti stanno facendo, vero?) Rileveranno molti degli stessi problemi che i test di integrazione troverebbero che verrebbero persi dai test unitari, ma non è vero il contrario.
Voo

24

Sì, è possibile avere troppi test unitari. Se hai una copertura del 100% con test unitari e nessun test di integrazione, ad esempio, hai un chiaro problema.

Alcuni scenari:

  1. Ingegneri eccessivi dei test per un'implementazione specifica. Quindi devi buttare via i test unitari quando esegui il refactoring, per non dire quando cambi l'implementazione (un punto dolente molto frequente quando esegui le ottimizzazioni delle prestazioni).

    Un buon equilibrio tra unit test e test di integrazione riduce questo problema senza perdere una copertura significativa.

  2. Potresti avere una copertura ragionevole per ogni commit con il 20% dei test che hai, lasciando il restante 80% per l'integrazione o almeno passaggi di test separati; i principali effetti negativi che si verificano in questo scenario sono i cambiamenti lenti poiché è necessario attendere molto tempo per l'esecuzione dei test.

  3. Modifichi troppo il codice per permetterti di testarlo; ad esempio, ho visto molti abusi di IoC su componenti che non richiederanno mai di essere modificati o almeno è costoso e poco prioritario generalizzarli, ma le persone investono molto tempo a generalizzarli e refactoring per consentire alle unità di testarli .

Concordo in particolare con il suggerimento di ottenere una copertura del 50% sul 100% dei file, anziché una copertura del 100% sul 50% dei file; focalizzare i tuoi sforzi iniziali sui casi positivi più comuni e sui casi negativi più pericolosi, non investire troppo sulla gestione degli errori e sui percorsi insoliti, non perché non siano importanti ma perché hai un tempo limitato e un universo di test infinito, quindi è necessario stabilire le priorità in ogni caso.


2
Il che non è un problema con i test unitari, ma con l'organizzazione per avere le priorità sbagliate chiedendo un numero specifico per la copertura dei test unitari senza spendere le risorse per creare ed eseguire test adeguati ad altri livelli.
jwenting

2
Concordare fermamente sul n. 3 e lo estenderebbe anche al passaggio manuale in istanze di classi di livello inferiore a classi di livello superiore. Se una cosa di alto livello si affida a qualcosa di basso livello per fare qualcosa, va bene. Se nasconde i dettagli di ciò ai chiamanti, chiamerei quel buon design. Ma se poi fai qualcosa di basso livello nell'interfaccia di alto livello e fai passare i chiamanti perché rende i tuoi test carini, ora la coda sta scodinzolando il cane. (Se la cosa di basso livello viene riutilizzata in molti luoghi e cambia molto, ciò cambia le cose. Nella mia esperienza che non è stata tipica.)
johncip

Adoro la tua descrizione @johncip, sicuramente questo è un esempio frequente di come una bella classe diventa orribile aggiungendo un mucchio di parametri necessari non necessari al costruttore ...
Bruno Guardia,

19

Tieni presente che ogni test ha un costo e un vantaggio. Gli svantaggi includono:

  • un test deve essere scritto;
  • un test richiede (in genere una quantità molto piccola) di tempo per essere eseguito;
  • un test deve essere gestito con il codice - i test devono cambiare quando le API che stanno testando cambiano;
  • potrebbe essere necessario modificare il design per poter scrivere un test (anche se questi cambiamenti sono in genere migliori).

Se i costi superano i benefici, è meglio che un test non sia scritto. Ad esempio, se la funzionalità è difficile da testare, l'API cambia spesso, la correttezza è relativamente irrilevante e la possibilità che il test rilevi un difetto è bassa, probabilmente è meglio non scriverlo.

Per quanto riguarda il tuo particolare rapporto tra test e codice, se il codice è sufficientemente logico, allora quel rapporto può essere garantito. Tuttavia, probabilmente non vale la pena mantenere un rapporto così elevato in un'applicazione tipica.


12

Sì, esistono troppi test unitari.

Mentre il test è buono ogni test unitario è:

  • Un potenziale onere di manutenzione strettamente associato all'API

  • Tempo che potrebbe essere speso per qualcos'altro

  • Una fetta di tempo nella suite di unit test
  • Potrebbe non aggiungere alcun valore reale perché è in effetti un duplicato di qualche altro test che ha minuscole probabilità che qualche altro test passerà e questo test fallirà.

È saggio puntare a una copertura del codice del 100%, ma è tutt'altro che una serie di test ciascuno dei quali fornisce in modo indipendente una copertura del codice del 100% su un determinato punto di ingresso (funzione / metodo / chiamata ecc.).

Tuttavia, dato quanto sia difficile ottenere una buona copertura e scacciare i bug, la verità è probabilmente che esistono "test unitari sbagliati" o "troppi test unitari".

Pragmatica per la maggior parte del codice indica:

  1. Assicurati di avere una copertura del 100% dei punti di ingresso (tutto viene testato in qualche modo) e miri ad essere vicino alla copertura del codice del 100% dei percorsi "non errori".

  2. Testare eventuali valori min / max rilevanti o dimensioni

  3. Metti alla prova tutto ciò che pensi sia un caso speciale divertente, in particolare i valori "dispari".

  4. Quando trovi un bug aggiungi un unit test che avrebbe rivelato quel bug e pensa se aggiungere casi simili.

Per algoritmi più complessi considerare anche:

  1. Fare alcuni test di massa per più casi.
  2. Confronto del risultato con un'implementazione della "forza bruta" e controllo degli invarianti.
  3. Usando un metodo per produrre casi di test casuali e controllando la forza bruta e le condizioni post tra cui gli invarianti.

Ad esempio, controllare un algoritmo di ordinamento con alcuni input randomizzati e la convalida dei dati viene ordinato alla fine mediante la scansione.

Direi che il tuo capo tecnico sta proponendo test di "minimo culo nudo". Sto offrendo "test di alta qualità" e c'è uno spettro nel mezzo.

Forse il tuo senior sa che il componente che stai costruendo sarà incorporato in un pezzo più grande e l'unità testata più accuratamente quando integrata.

La lezione chiave è aggiungere test quando vengono trovati dei bug. Il che mi porta la mia migliore lezione sullo sviluppo di unit test:

Concentrarsi su unità non su sottounità. Se stai costruendo un'unità a partire da unità secondarie scrivi test molto basilari per le unità secondarie fino a quando non sono plausibili e ottieni una copertura migliore testando le unità secondarie attraverso le loro unità di controllo.

Quindi, se stai scrivendo un compilatore e devi scrivere una tabella dei simboli (diciamo). Ottieni la tabella dei simboli attiva e funzionante con un test di base e poi lavora (diciamo) al parser di dichiarazione che riempie la tabella. Aggiungi ulteriori test all'unità 'stand-alone' della tabella dei simboli solo se trovi dei bug. In caso contrario, aumentare la copertura mediante test unitari sul parser di dichiarazione e successivamente l'intero compilatore.

Questo offre il miglior rapporto qualità-prezzo (un test del tutto consiste nel testare più componenti) e lascia più capacità di riprogettazione e perfezionamento perché nei test tende a essere più stabile solo l'interfaccia "esterna".

Insieme alle pre-condizioni di test del codice di debug, post-condizioni, inclusi invarianti a tutti i livelli, si ottiene la massima copertura del test dall'implementazione minima del test.


4
Non direi che una copertura del 100% sia pragmatica. La copertura al 100% è uno standard estremamente elevato.
Bryan Oakley,

Sfortunatamente anche il metodo randomizzato può perdere errori. Non vi è alcun sostituto per le prove, anche se informali.
Frank Hileman,

@BryanOakley Punto preso. È un'esagerazione. Ma è più importante avvicinarsi ad esso che le persone danno credito. "Ho testato il percorso facile va bene" causerà sempre problemi in seguito.
Persixty,

@FrankHileman La domanda non era "Il test unitario è un buon sostituto per la progettazione accurata del software, la logica di controllo statico e gli algoritmi di prova", quindi la risposta è "no". Nessuno dei due metodi produrrà software di alta qualità per conto proprio.
Persixty,

3

In primo luogo, non è necessariamente un problema avere più linee di test rispetto al codice di produzione. Il codice di test è (o dovrebbe essere) lineare e di facile comprensione - la sua complessità necessaria è molto, molto bassa, indipendentemente dal fatto che sia o meno il codice di produzione. Se la complessità dei test inizia ad avvicinarsi a quella del codice di produzione, allora probabilmente hai un problema.

Sì, è possibile avere troppi test unitari: un semplice esperimento mentale mostra che è possibile continuare ad aggiungere test che non forniscono un valore aggiuntivo e che tutti quei test aggiunti possono inibire almeno alcuni refactoring.

Il consiglio di testare solo i casi più comuni è imperfetto, secondo me. Questi possono fungere da test del fumo per risparmiare tempo nei test di sistema, ma i test davvero preziosi rilevano casi difficili da esercitare in tutto il sistema. Ad esempio, l'iniezione controllata di errori degli errori di allocazione della memoria può essere utilizzata per esercitare percorsi di recupero che potrebbero altrimenti essere di qualità completamente sconosciuta. Oppure passa zero come valore che saprai verrà utilizzato come divisore (o un numero negativo che avrà la radice quadrata) e assicurati di non ottenere un'eccezione non gestita.

I prossimi test più preziosi sono quelli che esercitano i limiti estremi o i punti di confine. Ad esempio, una funzione che accetta mesi (basati su 1) dell'anno deve essere testata con 0, 1, 12 e 13, in modo da sapere che le transizioni valido-non valido si trovano nel posto giusto. È un test eccessivo utilizzare anche 2..11 per questi test.

Sei in una posizione difficile, nel senso che devi scrivere test per il codice esistente. È più facile identificare i casi limite mentre stai scrivendo (o stai per scrivere) il codice.


3

La mia comprensione del test unitario era di testare ogni metodo della classe per garantire che ogni metodo funzionasse come previsto.

Questa comprensione è sbagliata.

Prove di unità verifica la comportamento della unità in prova .

In tal senso, un'unità non è necessariamente "un metodo in una classe". Mi piace la definizione di un'unità di Roy Osherove in The Art of Unit Testing :

Un'unità è tutto il codice di produzione che ha lo stesso motivo per cambiare.

Sulla base di questo, un test unitario dovrebbe verificare ogni comportamento desiderato del codice. Dove il "desiderio" è più o meno preso dai requisiti.


Tuttavia, nella richiesta pull il mio responsabile tecnico ha notato che avrei dovuto concentrarmi su test di livello superiore.

Ha ragione, ma in un modo diverso da quello che pensa.

Dalla tua domanda capisco che tu sei il "tester dedicato" in quel progetto.

Il grande fraintendimento è che si aspetta che tu scriva unit test (al contrario di "test usando un framework di unit test"). Scrivere test ynit è responsabilità degli sviluppatori , non dei tester (in un mondo ideale, lo so ...). D'altra parte hai taggato questa domanda con TDD, il che implica esattamente questo.

Il tuo compito come tester è quello di scrivere (o eseguire manualmente) i moduli e / o i test delle applicazioni. E questo tipo di test dovrebbe principalmente verificare che tutte le unità funzionino insieme senza problemi. Ciò significa che devi selezionare i tuoi casi di test in modo che ogni unità venga eseguita almeno una volta . E quel controllo è che viene eseguito. Il risultato effettivo è meno importante poiché è soggetto a modifiche con requisiti futuri.

Per sottolineare ancora una volta l'analogia con l'automobile in discarica: quanti test vengono effettuati con un'auto alla fine della catena di montaggio? Esattamente uno: deve guidare da solo al parcheggio ...

Il punto qui è:

Dobbiamo essere consapevoli di quella differenza tra "test unitari" e "test automatizzati utilizzando un framework di test unitari".


Per me, la copertura del test unitario al 100% è un obiettivo elevato, ma anche se avessimo raggiunto solo il 50%, sapremmo che il 100% di quel 50% era coperto.

I test unitari sono una rete di sicurezza. Ti danno la sicurezza di riformattare il tuo codice per ridurre il debito tecnico o aggiungere nuovi comportamenti senza temere di violare comportamenti già implementati.

Non è necessaria la copertura del codice al 100%.

Ma hai bisogno di una copertura del comportamento al 100%. (Sì, la copertura del codice e la copertura del comportamento sono in qualche modo correlate, ma non sono identiche per il gusto di farlo.)

Se la copertura del comportamento è inferiore al 100%, l'esecuzione corretta della suite di test non significa nulla, dal momento che si sarebbe potuto modificare parte del comportamento non testato. E verrai notato dal tuo cliente il giorno dopo che la tua versione sarà online ...


Conclusione

Pochi test sono meglio di nessun test. Nessun dubbio!

Ma non esiste una cosa come avere troppi test unitari.

Questo perché ogni unit test verifica una singola aspettativa sul comportamento dei codici . E non puoi scrivere più unit test di quanto non ti aspetti dal tuo codice. E un buco nell'imbracatura di sicurezza è un'opportunità per un cambiamento indesiderato di danneggiare il sistema di produzione.


2

Assolutamente si. Ero un SDET per una grande azienda di software. Il nostro piccolo team doveva mantenere il codice di test che era gestito da un team molto più grande. Inoltre, il nostro prodotto presentava alcune dipendenze che introducevano costantemente cambiamenti di rottura, il che significa per noi una costante manutenzione dei test. Non avevamo la possibilità di aumentare le dimensioni della squadra, quindi abbiamo dovuto buttare via migliaia di test meno preziosi quando fallivano. Altrimenti, non saremmo mai in grado di tenere il passo con i difetti.

Prima di liquidare questo come un semplice problema di gestione, considera che molti progetti nel mondo reale soffrono di personale ridotto quando si avvicinano allo status legacy. A volte inizia persino a succedere subito dopo la prima versione.


4
"Inoltre, il nostro prodotto presentava alcune dipendenze che introducevano costantemente modifiche sostanziali, il che significa per noi una costante manutenzione dei test." - Quei test che dici richiedono un suono di manutenzione come quelli preziosi se le tue dipendenze si interrompono costantemente.
CodeMonkey

2
Questo non è un problema con i test, ma con l'organizzazione.
jwenting

2
@CodeMonkey Le dipendenze non si sono interrotte. Sono stati aggiornati in modi che hanno richiesto modifiche al nostro prodotto. Sì, i test erano preziosi, ma non altrettanto preziosi come gli altri. I test automatici sono molto utili quando il test manuale equivalente è difficile.
Mrog,

2
@jwenting Sì, è un problema organizzativo, non un problema di codice. Ma ciò non cambia il fatto che ci sono stati troppi test. Un test fallito che non può essere studiato è inutile, indipendentemente dalla causa.
Mrog,

Che cos'è un "SDET"?
Peter Mortensen,

1

Avere più righe di codice di prova rispetto al codice prodotto non è necessariamente un problema, supponendo che tu stia rifattorizzando il tuo codice di prova per eliminare il copia-incolla.

Il problema è avere test che sono mirror della tua implementazione, senza significato commerciale - per esempio, test caricati con mock e stub e asserire solo che un metodo chiama qualche altro metodo.

Una grande citazione nel documento "perché la maggior parte dei test unitari è uno spreco" è che i test unitari dovrebbero avere un "oracolo di correttezza ampio, formale, indipendente e ... valore aziendale attribuibile"


0

Una cosa che non ho visto menzionato è che i tuoi test devono essere veloci e facili da eseguire per qualsiasi sviluppatore in qualsiasi momento.

Non devi effettuare il check-in per il controllo del codice sorgente e attendere un'ora o più (a seconda della dimensione della tua base di codice) prima che i test vengano completati per vedere se la tua modifica ha rotto qualcosa - vuoi essere in grado di farlo su la propria macchina prima di effettuare il check-in al controllo del codice sorgente (o almeno, prima di inviare le modifiche). Idealmente, dovresti essere in grado di eseguire i test con un singolo script o la pressione di un pulsante.

E quando esegui questi test localmente, vuoi che vengano eseguiti velocemente, nell'ordine dei secondi. Più lento, e sarai tentato di non eseguirli abbastanza o per niente.

Quindi, avere così tanti test che eseguirli tutti richiede pochi minuti o avere alcuni test eccessivamente complessi, potrebbe essere un problema.

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.