2010-08-08 10 views
20

Attualmente mi piacciono 10 test che testano ogni volta che il mio pezzo di Tetris non si muove verso sinistra se c'è un pezzo nel percorso o un muro. Ora, dovrò testare lo stesso comportamento per il movimento giusto.È corretto copiare e incollare i test unitari quando la logica è sostanzialmente la stessa?

È troppo male se copio solo i 10 test che ho già per il movimento sinistro e apporto solo le modifiche necessarie e faccio lo stesso anche per il codice stesso? O dovrei andare di nuovo e fare ogni test dall'inizio, anche se la logica è fondamentalmente la stessa?

risposta

30

Prova ad adottare il terzo approccio che non hai menzionato, quello di refactoring del codice in modo da poter condividere una implementazione del test tra tutti e 10 i test.

Il jist è che duplicare il codice è quasi sempre la cosa sbagliata da fare. In questo esempio è possibile rifattorizzare il codice di controllo in un metodo chiamato, ad esempio IsTetrisPieceUnableToMoveLeftBecauseOfAPieceOrAWall. Io vado sempre per nomi di metodi molto descrittivi come quello quando scrivo un po 'di funzionalità "condivisa" per un test unitario in quanto rende straordinariamente chiaro ciò che viene fatto/testato.

+3

'Is_Tetris_piece_unable_to_move_left_because_of_a_piece_or_a_wall' – Inverse

+2

Grazie a Dio per il completamento automatico. – mpen

+3

@Inverse, sicuro, se i caratteri di sottolineatura lo fanno per te =) – Rob

14

Il codice di prova è come qualsiasi altro codice e deve essere mantenuto e refactored.

Ciò significa che se si dispone di una logica condivisa, estrarla nella propria funzione.

Alcune librerie di test di unità come la famiglia xUnit hanno attributi specifici di test, configurazione e rimozione per tale codice condiviso.

Vedere la domanda relativa this - "Perché il codice copia incolla è pericoloso?".

7

Non c'è niente di sbagliato con il copia-incolla, ed è un buon punto di partenza. In effetti, è meglio che da zero, come se avessi codice funzionante (test o altro), quindi il copia-incolla è più affidabile che da zero, oltre che più veloce.

Tuttavia, questo è solo il passaggio 1. Il passaggio 2 è il refactoring per la comunanza, e il passaggio 1 è solo per aiutarti a vedere quella comunanza. Se puoi già vederlo chiaramente senza copiare (a volte è più facile copiarlo prima e poi esaminare, a volte non lo è, e dipende dalla persona che lo fa) quindi saltare il passaggio 1.

1

Se si sta ripetendo il codice, allora devi refactoring. La tua situazione è un problema comune e viene risolta utilizzando "Parameteric Testing". Il test parametrico quando supportato dal cablaggio di test consente di passare più set di valori di input come parametri. Potresti anche voler cercare i test Fuzz, ho trovato che è utile in situazioni come questa.

+0

Come è utile il test fuzz nell'esempio fornito? – Dave

22

Ho una posizione alquanto controversa su questo. Mentre la duplicazione del codice deve essere evitata il più possibile nel codice di produzione, non è così male per il codice di test. Produzione e test di codice si differenziano per la natura e l'intento:

  • Codice di produzione possono permettersi una certa complessità in modo da essere comprensibile/mantenibile. Vuoi che il codice sia al livello di astrazione giusto e che il design sia coerente. Questo è ok perché hai dei test e puoi assicurarti che funzioni. La duplicazione del codice nel codice di produzione non sarebbe un problema se si avesse una copertura del codice del 100% a livello logico. Questo è davvero difficile da raggiungere, quindi la regola è: evitare la duplicazione e massimizzare la copertura del codice.

  • Il codice di prova d'altra parte deve essere il più semplice possibile. È necessario assicurarsi che il codice di test verifichi effettivamente ciò che dovrebbe. Se i test sono complicati, potresti finire con bug nei test o nei test sbagliati - e non hai test per i test, quindi la regola è: mantienilo semplice. Se il codice di prova è duplicato, questo non è un grosso problema quando qualcosa cambia. Se la modifica viene applicata solo in un test, l'altro non funzionerà finché non lo correggi.

Il punto principale che voglio fare è che la produzione e il codice di prova hanno una natura diversa. Quindi è sempre una questione di buon senso, e non sto dicendo che non dovresti calcolare il codice di test, ecc. Se puoi calcolare qualcosa nel codice di test e sei sicuro che sia ok, allora fallo. Ma per il codice di prova, preferirei la semplicità rispetto all'eleganza, mentre per il codice di produzione, preferirei l'eleganza alla semplicità. L'optimum è ovviamente avere una soluzione semplice ed elegante :)

PS: Se davvero non sei d'accordo, per favore lascia un commento.

+1

+1, trovo il tuo argomento convincente. Forse potremmo dire se il codice ur ha una complessità di livello x, quindi deve essere testato. Questo vale anche per il codice di prova. Quindi, se un adeguato refactoring aumenta la complessità del codice di test sopra x, allora o (1) refactor e si aggiunge un altro livello di test; o (2) Keep It Simple Stupid. – emory

+0

Concordo con il punto che il codice di prova dovrebbe essere semplice.Ma, allo stesso tempo, dovrebbe essere mantenibile e duplicare il codice non è quello che vorresti fare –

+2

@ P.K In realtà, il codice con duplicazione è per la maggior parte del tempo più facile da capire, perché la complessità è bassa (meno astrazione). Quindi la manutenzione non è difficile, ma potrebbe essere un po 'ripetitiva. Nell'ingegneria del software, la maggior parte del tempo è spesa * comprendendo * ciò che deve essere fatto, non * facendo * esso. Se mantenere i test è ripetitivo e noioso, va bene, così come dovrebbe essere. Il problema con la duplicazione è la paura di non aggiornare la logica in tutti i punti. Non puoi correre il rischio che il codice di produzione lasci un'incoerenza inosservata, ma nel codice di test, il test fallirà finché non lo cambierai. – ewernli

1

Ricorda che i test stanno spingendo contro il tuo codice. se trovi che i tuoi test sembrano duplicati tranne che per qualcosa di simile a sinistra/destra, allora forse c'è un codice sottostante che destra e sinistra stanno duplicando. Quindi potresti voler vedere se puoi refactoring il tuo codice da usare sia a sinistra che a destra e inviare una bandiera sinistra o destra ad esso.

+0

Non sono sicuro, come ho visto, la struttura del codice di test non dipende dalla struttura del codice testato.Ad esempio, posso usare lo stesso codice di test per testare molte diverse implementazioni di un Server HTTP – Dave

+0

L'idea alla base della rimozione della duplicazione nel test è che può aiutarti a creare un'interfaccia più astratta sul tuo SUT. Questo ti aiuterà a perfezionare gli oggetti che stai testando. Inoltre, ricorda anche che più duplicati hai nei tuoi test più alto sarà il carico di manutenzione o più alto sarà il tuo debito tecnico. – Gutzofter

1

Il sito xunitpatterns.org dice "no" (copia/incolla non è ok) perché può aumentare i costi quando i test devono essere aggiornati:

" Taglia e incolla "è un potente strumento per scrivere codice veloce ma lo produce molte copie dello stesso codice ciascuna delle quali deve essere mantenuta in parallelo.

e per ulteriori approfondimenti si collega anche l'articolo

By: Arie van Deursen, Leon Moonen, Alex van den Bergh, Gerard Kok

1

I concordato @Rob. Il codice ha bisogno di refactoring. Ma se non vuoi fare il refactoring del codice in questo momento, puoi andare e fare dei test parametrizzati. Lo stesso test funziona per diversi parametri. Vedere gli attributi TestCase e TestCaseSource in nunit.

consultare http://nunit.org/index.php?p=parameterizedTests&r=2.5

Problemi correlati