Scrittura test per codice esistente

67

Supponiamo che uno abbia un programma relativamente grande (diciamo 900k SLOC in C #), tutti commentati / documentati accuratamente, ben organizzati e funzionanti bene. L'intera base di codice è stata scritta da un singolo sviluppatore senior che non è più con la società. Tutto il codice è testabile così com'è e IoC è usato in tutto - tranne per qualche strana ragione per cui non hanno scritto nessun test unitario. Ora, la tua azienda vuole diramare il codice e desidera aggiungere test di unità per rilevare quando le modifiche interrompono la funzionalità di base.

  • L'aggiunta di test è una buona idea?
  • Se sì, come si potrebbe iniziare anche su qualcosa di simile?

Modifica

OK, quindi non mi aspettavo risposte che facessero buoni argomenti per conclusioni opposte. Il problema potrebbe essere comunque fuori dalle mie mani. Ho letto anche le "domande duplicate" e il consenso generale è che "scrivere test è buono" ... sì, ma non troppo utile in questo caso particolare.

Non penso di essere solo qui a contemplare la scrittura di test per un sistema legacy. Ho intenzione di mantenere le metriche su quanto tempo è trascorso e quante volte i nuovi test riscontrano problemi (e quante volte non lo fanno). Tornerò e aggiornerò questo anno circa da oggi con i miei risultati.

Conclusione

Quindi risulta che è praticamente impossibile aggiungere il test unitario al codice esistente con qualsiasi parvenza di ortodossia. Una volta che il codice sta funzionando, ovviamente non è possibile effettuare la luce rossa / verde dei test, di solito non è chiaro quali comportamenti sono importanti da testare, non è chiaro da dove cominciare e sicuramente non è chiaro quando hai finito. Davvero anche chiedendo questa domanda manca il punto principale di scrivere test in primo luogo. Nella maggior parte dei casi ho trovato più facile ri-scrivere il codice usando TDD piuttosto che decifrare le funzioni previste e aggiungere retroattivamente i test unitari. Quando si risolve un problema o si aggiunge una nuova funzionalità, si tratta di una storia diversa, e credo che questo sia il momento di aggiungere test unitari (come indicato in seguito). Alla fine la maggior parte del codice viene riscritta, spesso prima di quanto ti aspetteresti: adottando questo approccio sono stato in grado di aggiungere una copertura di test a una porzione sorprendentemente ampia della base di codice esistente.

    
posta Paul 06.08.2013 - 17:27
fonte

7 risposte

68

Mentre i test sono una buona idea, l'intenzione era che il programmatore originale li costruisse mentre stava costruendo l'applicazione per acquisire le sue conoscenze su come dovrebbe funzionare il codice e su cosa potrebbe rompersi, che sarebbe poi stato trasferito a te.

Nell'adottare questo approccio, c'è un'alta probabilità che tu scriva i test che hanno meno probabilità di interrompersi e perdi la maggior parte dei casi limite che sarebbero stati scoperti durante la creazione dell'applicazione.

Il problema è che la maggior parte del valore verrà da quei "trucchi" e da situazioni meno ovvie. Senza questi test, la suite di test perde praticamente tutta la sua efficacia. Inoltre, la società avrà un falso senso di sicurezza intorno alla loro applicazione, in quanto non sarà significativamente più efficace nella regressione.

Tipicamente il modo di gestire questo tipo di codebase è scrivere test per il nuovo codice e per il refactoring del vecchio codice fino a quando la base di codice legacy è completamente refactored.

Anche vedi .

    
risposta data 06.08.2013 - 18:02
fonte
36

Sì, aggiungere test è sicuramente una buona idea.

Dici che è ben documentato e che ti mette in una buona posizione. Prova a creare test usando quella documentazione come guida, concentrandoti su parti del sistema che sono critiche o soggette a frequenti cambiamenti.

Inizialmente, la dimensione pura della base di codice probabilmente sembrerà schiacciante rispetto alla piccola quantità di test, ma non c'è un approccio big-bang e iniziare da qualche parte è più importante che angosciante su cosa l'approccio migliore sarà.

Consiglierei il libro di Michael Feathers, Lavorare efficacemente con il codice legacy , per alcuni consigli utili e dettagliati.

    
risposta data 06.08.2013 - 17:58
fonte
21

Non tutti i test unitari hanno lo stesso beneficio. Il vantaggio di un test unitario arriva quando fallisce. Meno è probabile che fallisca, meno è benefico. È probabile che il codice nuovo o modificato di recente contenga errori piuttosto che codice modificato raramente che è ben testato nella produzione. Pertanto, i test unitari su codice nuovo o modificato di recente hanno maggiori probabilità di essere più vantaggioso.

Non tutti i test unitari hanno lo stesso costo. È molto più semplice eseguire il test del codice triviale che hai progettato tu stesso oggi rispetto al codice complesso che qualcun altro ha progettato molto tempo fa. Inoltre, i test durante lo sviluppo di solito risparmiano tempo di sviluppo. Sul codice legacy i risparmi sui costi non sono più disponibili.

In un mondo ideale, avresti tutto il tempo che ti serve per testare il codice legacy, ma nel mondo reale, a un certo punto, è ovvio che i costi associati all'aggiunta dei test unitari al codice precedente supereranno i benefici . Il trucco è identificare quel punto. Il controllo della versione può aiutarti mostrando il codice modificato più di recente e più frequentemente modificato, e puoi iniziare mettendo quelli sotto il test unitario. Inoltre, quando apporti modifiche in futuro, metti quelle modifiche e il codice strettamente correlato sotto unit test.

Seguendo questo metodo, alla fine avrai una copertura abbastanza buona nelle aree più vantaggiose. Se invece trascorri mesi prima di riprendere i test unitari prima di riprendere le attività generatrici di entrate, questa potrebbe essere una decisione auspicabile per la manutenzione del software, ma è una pessima decisione aziendale.

    
risposta data 06.08.2013 - 20:03
fonte
8

Is adding tests a good idea?

Assolutamente, anche se trovo un po 'difficile credere che il codice sia pulito e che funzioni bene e usi tecniche moderne e semplicemente non abbia test unitari. Sei sicuro che non siano seduti in una soluzione separata?

Ad ogni modo, se estendi / gestisci il codice, allora i test di unità reali sono inestimabili per quel processo.

If so, how would one even start on something like this?

Un passo alla volta. Se non conosci i test unitari, impara un po '. Una volta a tuo agio con i concetti, scegli una piccola sezione del codice e scrivi test per questo. Poi il prossimo e il prossimo. La copertura del codice ti può aiutare a trovare i punti che hai perso.

Probabilmente è meglio scegliere cose pericolose / rischiose / vitali da testare per prime, ma potresti essere più efficace testare qualcosa di diretto per entrare in un solco prima - specialmente se tu / il team non sei abituato alla base di codice e / o test delle unità.

    
risposta data 06.08.2013 - 17:34
fonte
3

Sì, fare test è una buona idea. Aiuteranno a documentare il codice di base esistente come previsto e a rilevare eventuali comportamenti imprevisti. Anche se inizialmente i test falliscono, lasciali, quindi rifatta il codice in un secondo momento in modo che passino e si comportino come previsto.

Inizia a scrivere test per classi più piccole (quelle che non hanno dipendenze e sono relativamente semplici) e passa a classi più grandi (quelle che hanno dipendenze e sono più complesse). Ci vorrà molto tempo, ma sii paziente e persistente in modo da poter eventualmente coprire il codice base il più possibile.

    
risposta data 06.08.2013 - 17:33
fonte
3

OK, darò l'opinione contraria ....

L'aggiunta di test a un sistema esistente funzionante sta per alterare quel sistema, a meno che non lo sia, il sistema è tutto scritto fin dall'inizio con sbeffeggiamenti. Ne dubito, anche se è del tutto possibile che abbia una buona separazione di tutti i componenti con confini facilmente definibili su cui inserire le tue finte interfacce. Ma se non lo è, allora dovrai fare dei cambiamenti piuttosto significativi (relativamente parlando) che potrebbero distruggere le cose. Nel migliore dei casi, trascorrerai un sacco di tempo scrivendo questi test, tempo che potrebbe essere meglio speso scrivendo invece un carico di documenti di progettazione dettagliata, documenti di analisi d'impatto o documenti di configurazione della soluzione. Dopotutto, questo è il lavoro che il tuo capo vuole fare più dei test unitari. Non è vero?

Ad ogni modo, non aggiungerei nessun test unitario di qualsiasi tipo.

Mi concentrerei su strumenti di test esterni e automatizzati che ti forniranno una copertura ragionevole senza cambiare nulla. Poi, quando arrivi a fare delle modifiche ... è in quel momento che puoi iniziare ad aggiungere test unitari all'interno del codebase.

    
risposta data 13.08.2013 - 23:36
fonte
2

Spesso mi sono imbattuto in questa situazione, ho ereditato una grande base di codice senza adeguata o nessuna copertura di test, e ora sono responsabile di aggiungere funzionalità, correggere bug, ecc.

Il mio consiglio è di assicurarmi e testare ciò che aggiungi, e se correggi bug o alterni casi d'uso nel codice corrente, allora prova l'autore. Se devi toccare qualcosa, scrivi test a quel punto.

Quando questo si rompe è quando il codice esistente non è strutturato bene per il test delle unità, quindi impieghi molto tempo per il refactoring in modo da poter aggiungere test per modifiche minori.

    
risposta data 06.08.2013 - 20:28
fonte

Leggi altre domande sui tag