Se il codice di prova dell'unità "odori" è davvero importante?

52

Solitamente mi limito a lanciare i miei test unitari usando copia e incolla e ogni altro tipo di cattiva pratica. I test unitari di solito finiscono per sembrare abbastanza brutti, sono pieni di "odore di codice", ma questo importa davvero? Mi dico sempre finché il codice "reale" è "buono", questo è tutto ciò che conta. Inoltre, i test unitari di solito richiedono vari "hack puzzolenti" come le funzioni di stub.

Quanto dovrei essere preoccupato per i test unitari mal progettati ("maleodoranti")?

    
posta Buttons840 18.05.2011 - 21:41
fonte

12 risposte

72

Gli odori del test unitario sono importanti? Sì, sicuramente. Tuttavia, sono diversi dagli odori del codice perché i test unitari hanno uno scopo diverso e hanno un diverso insieme di tensioni che ne informano il design. Molti odori nel codice non si applicano ai test. Data la mia mentalità TDD, direi che gli odori test unitari sono più importanti degli odori di codice perché il codice è lì solo per soddisfare i test.

Ecco alcuni odori di test unitari comuni:

  • Fragilità : i tuoi test falliscono spesso e inaspettatamente anche per modifiche al codice apparentemente banali o non correlate?
  • Perdita di stato : i test falliscono in modo diverso a seconda, ad esempio, dell'ordine in cui vengono eseguiti?
  • Setup / Teardown Bloat : i blocchi di setup / teardown sono lunghi e crescono più a lungo? Eseguono qualsiasi tipo di logica aziendale?
  • Runtime lento : i test richiedono molto tempo per essere eseguiti? Qualcuno dei tuoi test di unità individuali impiega più di un decimo di secondo a correre? (Sì, sono serio, un decimo di secondo.)
  • Attrito : i test esistenti rendono difficile la scrittura di nuovi test? Ti ritrovi a dover lottare con errori di test spesso durante il refactoring?

L'importanza degli odori è che essi sono utili indicatori di design o altre questioni più fondamentali, ad esempio "dove c'è fumo, c'è fuoco". Non cercare solo gli odori di prova, cerca anche la loro causa sottostante.

Qui, d'altra parte, ci sono alcune buone pratiche per i test unitari:

  • Feedback rapido e mirato : i test dovrebbero isolare rapidamente l'errore e fornirti informazioni utili sulla sua causa.
  • Riduci a icona distanza codice test : dovrebbe esserci un percorso chiaro e breve tra il test e il codice che lo implementa. Le lunghe distanze creano loop di feedback inutilmente lunghi.
  • Prova una cosa alla volta : i test unitari dovrebbero testare solo una cosa. Se hai bisogno di testare un'altra cosa, scrivi un altro test.
  • Un bug è un test che hai dimenticato di scrivere : cosa puoi imparare da questo errore per scrivere test migliori e più completi in futuro?
risposta data 18.05.2011 - 22:27
fonte
67

Sii preoccupato. Scrivi test unitari per dimostrare che il tuo codice funziona come ti aspetti. Ti permettono di refactoring rapidamente con fiducia. Se i test sono fragili, difficili da capire o se sono difficili da mantenere, ignorerai i test in errore o li spegnerai man mano che la base di codice si evolverà, annullando molti dei vantaggi della scrittura dei test.

    
risposta data 18.05.2011 - 21:48
fonte
19

Ho appena finito di leggere The Art of Unit Testing un paio di giorni fa. L'autore sostiene di mettere la massima cura nei test di unità mentre si esegue il codice di produzione.

Ho sperimentato test scritti male scritti e non mantenibili. Ho scritto alcuni dei miei. È praticamente garantito che se un test è un rompicoglioni da mantenere, non verrà mantenuto. Una volta che i test non sono sincronizzati con il codice in esame, sono diventati nidi di bugie e inganni. L'intero punto dei test unitari è quello di infondere la fiducia che non abbiamo rotto nulla (cioè, creano fiducia). Se i test non sono affidabili, sono peggio che inutili.

    
risposta data 18.05.2011 - 22:05
fonte
7

Fintanto che il tuo test dell'unità verifica effettivamente il tuo codice nella maggior parte dei casi. (Detto più apposta dato che a volte è difficile trovare tutti i risultati possibili). Penso che il codice "puzzolente" sia la tua preferenza personale. Scrivo sempre il codice in un modo in cui riesco a leggerlo e a capirlo in pochi secondi, piuttosto che scavare nella spazzatura e cercare di capire cosa sia. Soprattutto quando torni indietro dopo una quantità significativa di tempo.

Linea di fondo: il suo test, suppone che sia facile. Non ti vuoi confondere con il codice "puzzolente".

    
risposta data 18.05.2011 - 21:45
fonte
6

Sicuramente. Alcuni dicono "qualsiasi test è meglio di nessun test". Non sono assolutamente d'accordo: i test scritti male impantanano i tempi di sviluppo e finisci per perdere giorni a correggere i test "non funzionanti" perché non erano dei buoni test unitari in primo luogo. Per me al momento, le due cose su cui mi sto concentrando per rendere i miei test preziosi, piuttosto che un peso, sono:

Maintainability

Dovresti testare il risultato ( cosa succede ), non il metodo ( come succede). Il tuo set-up per il test dovrebbe essere il più possibile disaccoppiato dall'implementazione: solo impostare i risultati per le chiamate di servizio ecc. Che sono assolutamente necessari.

  • Utilizza un framework di simulazione per assicurarti che i tuoi test non dipendano da nulla di esterno
  • Favorisci gli stub su mock (se il tuo framework li distingue) ove possibile
  • Nessuna logica nei test! Se, switch, for-eaches, casi, try-catches ecc. Sono tutti grandi no-no, in quanto possono introdurre bug nel codice di test stesso

La leggibilità

Va bene consentire un po 'più di ripetizioni nei tuoi test, che normalmente non permetti nel codice di produzione, se li rende più leggibili. Basta bilanciare questo con la manutenibilità di cui sopra. Sii esplicito in ciò che sta facendo il test!

  • Cerca di mantenere uno stile "ordina, recita, asserisci" per i tuoi test. Questo separa la configurazione e le aspettative dello scenario, dall'azione eseguita e dal risultato che si asserisce.
  • Mantenere una logica asserzione per test (se il nome del test ha "e" in esso, potrebbe essere necessario scomporlo in più test)

In conclusione, dovresti essere molto interessato ai test "puzzolenti": possono finire per perdere tempo, senza fornire alcun valore.

Hai detto:

Unit testing usually requires various "smelly hacks" like stubbing functions.

Sembra che si possa sicuramente fare con la lettura di alcune tecniche di Unit Testing, come l'utilizzo di un framework di Mocking, per rendere la vita molto più semplice. Consiglio vivamente di The Art of Unit Testing , che copre quanto sopra e molto altro ancora. L'ho trovato illuminante dopo aver lottato con test scritti male, irrimediabilmente "maleodoranti" per molto tempo. È uno dei migliori investimenti in termini di tempo che ho fatto quest'anno!

    
risposta data 19.05.2011 - 02:42
fonte
5

Due domande per te:

  • Sei assolutamente sicuro di provare ciò che pensi stai testando?
  • Se qualcun altro guarda il test unitario, sarà in grado di capire quale codice dovrebbe essere ?

Ci sono modi per gestire compiti ripetitivi nei test di unità che sono più comunemente codice di installazione e cancellazione. In sostanza, si dispone di un metodo di impostazione di prova e di un metodo di abbattimento del test: tutti i framework di test delle unità hanno il supporto per questo.

I test unitari dovrebbero essere piccoli e facilmente comprensibili. Se non lo sono e il test fallisce, come risolveresti il problema in un periodo di tempo ragionevolmente breve. Rendilo semplice per un paio di mesi lungo la strada quando devi tornare al codice.

    
risposta data 18.05.2011 - 21:49
fonte
5

Quando la spazzatura inizia a puzzare, è il momento di tirarla fuori. Il tuo codice di prova dovrebbe essere pulito come il tuo codice di produzione. Lo mostreresti a tua madre?

    
risposta data 18.05.2011 - 22:54
fonte
3

Oltre alle altre risposte qui.

Il codice di scarsa qualità nei test di unità non è limitato alla suite di test dell'unità.

Uno dei ruoli occupati da Test unitario è Documentazione.

La suite Unit Test è uno dei posti in cui si cerca di scoprire come si intende utilizzare un'API.

Non è improbabile che i chiamanti della tua API copino parti della tua suite di test unitarie, portando al tuo cattivo codice della suite di test che infetta il codice live altrove.

    
risposta data 19.05.2011 - 11:54
fonte
3

Quasi non ho inviato la mia risposta in quanto mi ci è voluto un po 'per capire come affrontare questo come una domanda legittima.

I motivi per cui i programmatori si dedicano alle "migliori pratiche" non sono per ragioni estetiche o perché vogliono un codice "perfetto". È perché risparmia tempo.

  • Risparmia tempo perché un buon codice è più facile da leggere e capire.
  • Consente di risparmiare tempo perché quando è necessario trovare una correzione di un bug è più facile e più veloce da individuare.
  • Risparmia tempo perché quando vuoi estendere il codice è più facile e veloce farlo.

Quindi la domanda che mi chiedi (dal mio punto di vista) è che dovrei risparmiare tempo o scrivere codice che mi farà perdere tempo?

A quella domanda posso solo dire quanto è importante il tuo tempo?

FYI: le patch di stub, mocking e scimmia hanno tutti usi legittimi. Loro "odorano" solo quando il loro uso non è appropriato.

    
risposta data 18.05.2011 - 22:26
fonte
2

Cerco in particolare di NON rendere i miei test unitari troppo robusti. Ho visto test unitari che iniziano a gestire gli errori in nome dell'essere robusti. Ciò che si finisce con sono test che inghiottono i bug che stanno cercando di catturare. I test unitari devono anche fare cose strane abbastanza spesso per far funzionare le cose. Pensa a tutta l'idea degli accessor privati usando la riflessione ... se vedessi un mucchio di quelli in tutto il codice di produzione, sarei preoccupato 9 volte su 10. Penso che si debba dedicare più tempo a ciò che viene testato , piuttosto che la pulizia del codice. I test dovranno essere cambiati abbastanza spesso comunque se fai qualche refactoring importante, quindi perché non limitarti a unirli insieme, avere un po 'meno i sentimenti di proprietà e essere più motivati a riscriverli o rielaborarli quando sarà il momento?

    
risposta data 18.05.2011 - 22:49
fonte
2

Se stai cercando una copertura pesante e di basso livello, trascorri più tempo o più nel codice di prova come nel codice del prodotto quando esegui modifiche gravi.

A seconda della complessità della configurazione del test, il codice potrebbe essere più complesso. (httpcontext.current contro il mostro orribile di provare a costruire uno falso con precisione, per esempio)

A meno che il tuo prodotto non sia qualcosa in cui raramente si apportano modifiche alle interfacce esistenti e i tuoi input a livello di unità sono molto semplici da configurare, sarei al massimo preoccupato per la comprensione dei test come prodotto reale.

    
risposta data 18.05.2011 - 23:23
fonte
0

Gli odori di codice sono solo un problema nel codice che richiede di essere modificato o compreso a un certo punto nel tempo.

Quindi penso che dovresti correggere gli odori del codice quando devi "chiudere" il test dell'unità dato, ma non prima.

    
risposta data 23.06.2011 - 15:37
fonte

Leggi altre domande sui tag