Best practice per il retrofit del codice legacy con test automatici


22

Sto per assumere il compito di reimplementare un'interfaccia già definita (un set di file di intestazione C ++) in una base di codice relativamente grande e vecchia. Prima di fare ciò, vorrei avere la copertura di test più completa possibile, in modo da poter rilevare gli errori di reimplementazione il più presto e facilmente possibile. Il problema è che la base di codice già esistente non è stata progettata per essere facilmente testabile, con classi e funzioni (molto) grandi, un alto grado di accoppiamento, funzioni con (molti) effetti collaterali, ecc.

Sarebbe bello conoscere qualsiasi esperienza precedente con compiti simili e alcuni buoni e concreti suggerimenti su come procedere con l'adeguamento dei test automatici (unità, integrazioni, regressione, ecc.) Al codice legacy.


1
Passaggio 1: ricerca overflow dello stack. La domanda è stata posta. Molte, molte volte
S. Lott,

Risposte:


20

Prima di tutto, leggi e lavora in modo efficace con il codice legacy di Michael Feathers: è un aiuto indispensabile per tali compiti.

Quindi, alcune note:

  • hai una specifica / un contratto preciso per l'interfaccia o hai praticamente l'implementazione esistente solo come "specifica"? Nel primo caso è più semplice eseguire una riscrittura completa da zero, nel secondo è difficile da impossibile.
  • se si desidera reimplementare l'interfaccia, il modo più utile di spendere le risorse di test è scrivere test solo sull'interfaccia. Naturalmente, questo non si qualifica come test unitario in senso stretto, piuttosto come test funzionale / di collaudo, ma non sono un purista :-) Tuttavia, questi test sono riutilizzabili e consentono di confrontare direttamente i risultati delle due implementazioni affiancate .
  • nel complesso, preferirei il refactoring del codice esistente piuttosto che riscriverlo da zero, a meno che non sia completamente non mantenibile. (Ma in questo caso, come hai intenzione di scrivere comunque dei test unitari?) Dai un'occhiata a questo post di Joel per una discussione più dettagliata sull'argomento. Avere creato una serie di test di accettazione rispetto all'interfaccia ti offre una rete di sicurezza sottile ma utile, contro la quale puoi iniziare a riformattare cautamente il codice esistente per renderlo testabile (usando le idee dal libro di Feathers).

Lo farei +3 se potessi. Il WELC è una lettura essenziale e sicuramente va per un refactoring ...
Johnsyweb,

Un piccolo commento sul secondo punto è che per i sistemi legacy, i test dovrebbero essere eseguiti secondo la mentalità del test di caratterizzazione . Cioè, catturare fedelmente l'attuale comportamento del software e astenersi dal cambiare il comportamento anche se alcuni dei risultati del test sembrano strani o non piacevoli secondo la mentalità del test unitario. (Tra l'altro questa idea proviene anche dall'autore del WELC.)
rwong

@rwong, davvero. Senza una specifica dettagliata o un proprietario del prodotto informato, è impossibile per lo sviluppatore decidere se un comportamento specifico del programma a) è intenzionale e richiesto, b) non intenzionale ma ormai gli utenti dipendono da esso, c) un bug che effettivamente danneggia gli utenti, d) un bug totalmente inosservato fino ad ora. Nei primi due casi, la "correzione" in realtà danneggerebbe gli utenti e, nell'ultimo caso, la correzione, sebbene teoricamente corretta, non fornirebbe alcun vantaggio visibile.
Péter Török,

4

Il metodo migliore è sapere è il metodo Mikado. http://mikadomethod.wordpress.com/2010/08/04/the-mikado-method-book/ Questa è solo la generalizzazione di una tecnica semplice ma è l'unico modo che conosco per iniziare a migliorare la qualità del codice in una grande base di codice senza correre rischi inutili.

WEWLC è anche un ottimo libro a riguardo, ma essere scritto in C ++ non è sempre utile con il codice Java o Ruby.


2

I test di adattamento retro su una vecchia base di codice possono essere abbastanza difficili se sono monolitici nel design.

Se possibile (hai il tempo / i soldi), un modo per andare avanti sarebbe il refactoring del codice in unità più testabili.


1

Vorrei aggiungere un link . Ci sono alcuni esempi di implementazioni non così facilmente verificabili reinserite in codice più xUnit friendly. Per quanto riguarda l'approccio generale vai a provare i link già menzionati (Joel post, Working With Legacy code

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.