Contrariamente alle altre risposte, è importante notare che alcuni modi per testare possono diventare fragili quando il sistema in prova (SUT) viene refactored, if il test è whitebox.
Se utilizzo un framework di simulazione che verifica l' ordine dei metodi chiamati sui mock (quando l'ordine è irrilevante perché le chiamate sono prive di effetti collaterali); quindi se il mio codice è più pulito con quelle chiamate di metodo in un ordine diverso e io refactoring, allora il mio test si interromperà. In generale, i mock possono introdurre fragilità nei test.
Se sto controllando lo stato interno del mio SUT esponendo i suoi membri privati o protetti (potremmo usare "amico" in visual basic o scalare il livello di accesso "interno" e usare "internalsvisibleto" in c #; in molti OO lingue, tra cui c # a " specifico-test-sottoclasse " potrebbe essere usato) quindi improvvisamente lo stato interno della classe sarà importante - potresti refactoring della classe come una scatola nera, ma i test della scatola bianca falliranno. Supponiamo che un singolo campo venga riutilizzato per significare cose diverse (non buone pratiche!) Quando il SUT cambia stato - se lo dividiamo in due campi, potremmo aver bisogno di riscrivere test non funzionanti.
Le sottoclassi specifiche del test possono anche essere utilizzate per testare metodi protetti - il che può significare che un refactoring dal punto di vista del codice di produzione è un cambiamento di rottura dal punto di vista del codice di test. Spostare alcune linee dentro o fuori un metodo protetto potrebbe non avere effetti collaterali di produzione, ma interrompere un test.
Se utilizzo " ganci di prova " o qualsiasi altro codice di compilazione specifico o condizionale, può essere difficile assicurati che i test non si interrompano a causa delle fragili dipendenze dalla logica interna.
Quindi, per evitare che i test si uniscano ai dettagli interni intimi del SUT, può aiutare a:
- Usa gli stub anziché i mock, se possibile. Per maggiori informazioni vedi il blog di Fabio Periera sui test tautologici e il mio blog sui test tautologici .
- Se utilizzi i mock, evita di verificare l'ordine dei metodi chiamati, a meno che non sia importante.
- Cerca di evitare di verificare lo stato interno del tuo SUT - usa la sua API esterna, se possibile.
- Cerca di evitare la logica specifica del test nel codice di produzione
- Cerca di evitare l'utilizzo di sottoclassi specifiche del test.
Tutti i punti sopra riportati sono esempi di accoppiamenti white-box usati nei test. Quindi, per evitare completamente il refactoring dei test di rottura, usa il test black-box del SUT.
Dichiarazione di non responsabilità: allo scopo di discutere del refactoring qui, sto usando la parola un po 'più in generale per includere il cambiamento di implementazione interna senza effetti esterni visibili. Alcuni puristi potrebbero non essere d'accordo e fare riferimento esclusivamente al libro Refactoring di Martin Fowler e Kent Beck, che descrive le operazioni di refactoring atomico.
In pratica, tendiamo a prendere passi non violenti leggermente più grandi delle operazioni atomiche qui descritte, e in particolare le modifiche che lasciano il codice di produzione che si comporta in modo identico dall'esterno potrebbero non lasciare passare i test. Ma penso che sia giusto includere "un algoritmo sostitutivo per un altro algoritmo che ha un comportamento identico" come un refactoring, e penso che Fowler sia d'accordo. Lo stesso Martin Fowler afferma che il refactoring potrebbe rompere i test:
When you write a mockist test, you are testing the outbound calls of the SUT to ensure it talks properly to its suppliers. A classic test only cares about the final state - not how that state was derived. Mockist tests are thus more coupled to the implementation of a method. Changing the nature of calls to collaborators usually cause a mockist test to break.
[...]
Coupling to the implementation also interferes with refactoring, since
implementation changes are much more likely to break tests than with
classic testing.
Fowler - Mocks aren't stubs