2009-10-09 11 views
67

Avete mai aggiunto test di unità, dopo il fatto, a codice legacy? Quanto è stato complicato il codice e quanto è difficile stubare e deridere tutto? Il risultato finale è stato utile?Aggiunta di test di unità al codice precedente

+4

Controllerò out "Lavorare efficacemente con il codice legacy". Spero che mi dia dei buoni consigli su come scrivere wrapper per tutte queste dipendenze statiche! – BuckeyeSoftwareGuy

+0

Dai un'occhiata a [Rhino Mocking e TDD con codice precedente] (http://stackoverflow.com/questions/3519993/rhino-mocking-and-tdd-with-legacy-code/21612055#21612055) – Lijo

risposta

50

Il modo migliore, ho trovato, è quello di aggiungere in modo incrementale i test unitari, non solo per saltare e dire che ora testeremo l'applicazione.

Quindi, se si sta andando a toccare il codice, per correzioni di errori o refactoring, quindi prima scrivere i test unitari. Per i bug test unitari ti aiuterà a capire dove si trova il problema, dato che puoi duplicarlo.

Se si esegue il refactoring, si desidera scrivere test di unità, ma è possibile che il test sia impossibile da scrivere, quindi potrebbe essere necessario trovare un livello alto, che richiami la funzione che verrà refactored e unit test che parte. Quindi, mentre rifatti la funzione offensiva, scrivi i tuoi test in modo da assicurarti che funzioni come dovrebbe.

Non c'è un modo semplice per farlo.

Questa domanda può aiutare con più suggerimenti. How do you introduce unit testing into a large, legacy (C/C++) codebase?

+7

+1 per aggiungere in modo incrementale i test. – TrueWill

4

Se si sta pianificando di eseguire il refactoring del codice legacy, la creazione di tali test di unità è indispensabile. Non preoccuparti per il mocking o lo stub - preoccupati di testare gli input e gli output del sistema in modo che le tue modifiche o gli sforzi di refactoring non interrompano la funzionalità corrente.

Non mentirò a te, l'installazione a posteriori di test di unità su codice precedente è difficile, ma ne vale la pena.

+0

Ho iniziato a creare unità test per il codice legacy su cui ho lavorato. Tuttavia, mi sono reso conto che ho scritto test di integrazione, non test unitari perché creo dati reali e li inserisco nel database. Non vedo un modo per creare mock e stub puri per questo codice legacy perché non è strutturato per il test. –

8

Sì, ed è generalmente doloroso. Ho spesso finito per dover scrivere test di integrazione.

Il libro The Art of Unit Testing ha alcuni buoni consigli su questo. Raccomanda anche il libro Working Effectively with Legacy Code; Non ho ancora letto quest'ultimo, ma è nel mio stack.

MODIFICA: ma sì, anche la copertura del codice minima è valsa la pena. Mi ha dato fiducia e una rete di sicurezza per il refactoring del codice.

EDIT: Ho letto che funziona efficacemente con il codice legacy ed è eccellente.

+3

+1 per "Lavorare efficacemente con il codice legacy": pieno di ottimi consigli; in effetti vale la pena leggerlo anche per gli ambienti greenfield, proprio come una grande risorsa per la costruzione di codice per la testabilità. – itowlson

+1

+1 per l'idea di sostituire i test unitari con i test di integrazione. Con il giusto beffardo, i primi sono abbastanza buoni, molto spesso – DVK

36

Il libro di Michael Feathers "Lavorare efficacemente con il codice legacy" è un intero libro che tratta questo argomento. Michael afferma che è spesso troppo difficile introdurre test per il codice legacy perché non è strutturato per essere testabile. Quello che ho ottenuto di più dal libro è stato un paio di schemi chiamati "Sprout functions" e "Sprout classes". Una funzione di sprout è quella che incapsula il cambiamento che è necessario apportare nel codice. Quindi l'unità verifica solo queste funzioni. La classe sprout è la stessa idea tranne che la nuova funzionalità è contenuta in una classe.

5

Un'alternativa ai test di unità, introdotta anche in Funzionamento efficace con codice legacy è characterization tests. Ho avuto risultati interessanti con questi test. Sono più facili da configurare rispetto ai test unitari mentre esegui il test dal punto rispetto a quelli che possono essere testati (chiamati cucitura). Lo svantaggio è che quando un test fallisce, si ha meno indizio circa la posizione del problema in quanto l'area sottoposta a test può essere molto più grande rispetto ai test unitari. La registrazione aiuta qui.


Un quadro di test unitario come quelli della famiglia xUnit può essere utilizzato per scrivere test di caratterizzazione.

In tali test, scritti dopo i fatti, le asserzioni verificano il comportamento corrente del codice.A differenza dei test unitari, non dimostrano che il codice sia corretto, stanno solo fissando (caratterizzando) il comportamento corrente del codice.

Il processo è simile a quello del TDD ,:

  • scrivere un test per una porzione di codice
  • eseguirlo - sicuro
  • fissare la prova dal comportamento osservato del codice
  • eseguirlo - pass
  • ripetere

I test w fallire se si modifica il comportamento esterno del codice. Comportamento esterno del codice? suona familiare ? Sì lo è, eccoci qui. Ora puoi refactoring il codice.

Ovviamente il rischio dipende dalla copertura dei test di caratterizzazione.

4

Dai un'occhiata alla libreria di utility di test unità open source, ApprovalTests. Se sei uno sviluppatore .NET, il creatore, Llewellyn Falco, ha realizzato uno series of videos che mostra come utilizza ApprovalTests per migliorare il test delle unità per il codice nuovo e quello precedente.

1

ho parlato qualche tempo fa su idea di test Reversed Piramide in codice legacy a XPDays http://xpdays.com.ua/archive/xp-days-ukraine-2012/materials/legacy-code/

Questa presentazione dovrebbe rispondere alla domanda perché è così importante a volte per cominciare anche ad alto livello di integrazione/funzionale o test di accettazione quando si lavora con codice legacy. E poi lentamente, passo dopo passo, introducendo i test unitari. Non ci sono esempi di codice - scusate, ma potete trovarne molti nel libro di Michaels Feathers "Lavorare efficacemente con il codice legacy".

Inoltre, è possibile controllare Retacy Code Retreat http://www.jbrains.ca/legacy-code-retreat e cercare la riunione nella propria area.

5

Guarda anche il nuovo approccio nell'area del test delle unità di codice legacy - Asis project, si ispira al progetto ApprovalTests e ne condivide i concetti chiave.

Come accennato l'approccio ApprovalTests in this article:

Spesso si avere un enorme progetto di codice legacy in cui non si hanno prove a tutti, ma è necessario modificare il codice per implementare una nuova funzione, o refactoring . La cosa interessante del codice legacy è - Funziona! È funziona per anni, non importa come è scritto. E questo è un grande vantaggio di di quel codice. Con le approvazioni, con un solo test è possibile ottenere tutte le uscite possibili (HTML, XML, JSON, SQL o qualsiasi altra emissione potrebbe essere essere) e approvare, perché si sa - funziona! Dopo aver completato il test e aver approvato il risultato, sei davvero molto più sicuro con un refactoring , poiché ora hai "bloccato" tutti i comportamenti esistenti.

Lo strumento Asis tratta esattamente il mantenimento del codice legacy attraverso la creazione e l'esecuzione automatica di test di caratterizzazione.

Per ulteriori informazioni un'occhiata a

+0

Come questo non ha più upvotes? Se il repository fa quello che afferma di fare, questa dovrebbe essere la risposta selezionata. –

+0

Ha a che fare con gli effetti collaterali nelle funzioni, btw? Anche possibile risolvere questo problema? –