Rifattorizzare unit test?
Quando lavoriamo con codice legacy e dobbiamo apportare modifiche, per prima cosa scriviamo test sul comportamento corrente. In questo modo possiamo implementare i nuovi cambiamenti con fiducia. Possiamo persino effettuare il refactoring del codice.
Il codice legacy è spesso un codice errato e dopo un po 'di refactoring il codice potrebbe essere più semplice, più facile da testare. Dal momento che il refactoring è stato convalidato dai test, dovremmo anche refactoring dei test se possiamo renderli più semplici / chiari o mantenerli come sono stati scritti?
Risposte
I test automatizzati SONO codice, quindi mantenere questo codice ha senso, incluso il refactoring dei test quando appropriato. Però:
codice produttivo e test hanno requisiti di qualità diversi
- non investire tempo in cose che non contano
il codice produttivo dovrebbe avere un'unica fonte di verità, mentre i test dovrebbero essere in gran parte autonomi
- la duplicazione non è necessariamente un male
E come sottolinea Ewan, non dovresti mai cambiare il codice e i test contemporaneamente. Insieme, code + test sono un sistema di auto-test. Un cambiamento in una parte viene verificato eseguendolo insieme all'altra parte. Cambiare entrambi allo stesso tempo rinuncia a questa sicurezza. Ciò non è sempre possibile in pratica (ad esempio, quando si modifica una preoccupazione trasversale come una libreria standard sottostante), ma sarebbe sciocco rinunciare a questa sicurezza senza una necessità molto forte.
Motivi comuni per cui ho effettuato il refactoring dei test, in nessun ordine particolare: l'API da testare era cambiata, passando a un approccio di test diverso (ad es. framework di test (ad es. per ottenere rapporti di errore migliori o per utilizzare test parametrizzati), cambiare l'organizzazione del test (ad es. suite e casi in stile xUnit vs descrizione in stile RSpec), eliminare la duplicazione accumulata (ad es. estrazione di codice comune per creare un dispositivo) , ...
Quando lavoriamo con codice legacy e dobbiamo apportare modifiche, per prima cosa scriviamo test sul comportamento corrente. In questo modo possiamo implementare i nuovi cambiamenti con fiducia. Possiamo persino effettuare il refactoring del codice.
Ciò potrebbe riflettere a volte il tuo processo di lavoro, ma nella mia esperienza, un processo molto più efficiente è:
scrivi test
si effettua il refactoring per rendere più facile un cambiamento
implementate il cambiamento
In questo modo, diventa più evidente che si effettua il refactoring quando c'è una vera ragione per un cambiamento , non solo perché il codice "non è più pulito".
Ora prova ad applicare le stesse misure ai tuoi test: non rifattorizza i tuoi test perché "non sono più puliti" . Li esegui il refactoring quando iniziano a impedirti di apportare modifiche semplici al codice esistente.
Ad esempio, quando hai dieci test che chiamano tutti lo stesso metodo pubblico di una classe sotto test, mentre nel tuo codice di produzione quel metodo pubblico è chiamato solo in un posto, allora questa è una forma di duplicazione del codice da parte dei test che potrebbe impedirti di farlo cambiare la firma di quel metodo pubblico.
Di solito lo lascerei così a meno che tu non abbia davvero il requisito per quest'ultimo, o più generale: quando noti che questa duplicazione di codice richiede di apportare la stessa modifica ai tuoi test in diversi punti.
Potresti iniziare con il refactoring dei test.
I test acquisiscono ciò che fa l'applicazione legacy; una sorta di documentazione. I test ti dicono input e output, il codice ti dice processo. Se i test sono pessimi, riordinarli (a seconda di quanto sono pessimi) ti aiuterà a capire il codice.
È anche un ottimo modo per giudicare se i test aggiungono valore; un sistema legacy su cui ho lavorato aveva un'ottima copertura del codice, ma a un'ispezione i test affermavano cose inutili ... come assicurarsi che Getters e Setters funzionassero (testando il framework .NET non l'applicazione).
Una volta ottenuto un test pulito, avrai una migliore comprensione del codice e quindi potrai prendere decisioni migliori su come refactoring del codice.