Ho un'implementazione scheletrica, come nell'articolo 18 da Java efficace (discussione estesa qui ). È una classe astratta che fornisce 2 metodi pubblici methodA () e methodB () che chiamano i metodi delle sottoclassi per "riempire gli spazi vuoti" che non posso definire in modo astratto.
L'ho sviluppato per primo creando una classe concreta e test di unità di scrittura per esso. Quando è arrivata la seconda classe, sono stato in grado di estrarre comportamenti comuni, implementare le "lacune mancanti" nella seconda classe ed era pronto (ovviamente, i test unitari sono stati creati per la seconda sottoclasse).
Il tempo è passato e ora ho 4 sottoclassi, ognuna delle quali implementa 3 metodi protetti corti che sono molto specifici per la loro implementazione concreta, mentre l'implementazione scheletrica fa tutto il lavoro generico.
Il mio problema è che quando creo una nuova implementazione, scrivo di nuovo i test:
- La sottoclasse chiama un determinato metodo richiesto?
- Un determinato metodo ha una data annotazione?
- Ottengo i risultati attesi dal metodo A?
- Ottengo i risultati attesi dal metodo B?
Mentre vedi i vantaggi con questo approccio:
- Documenta i requisiti della sottoclasse attraverso i test
- Potrebbe fallire in fretta in caso di refactoring problematico
- Verifica la sottoclasse nel suo complesso e tramite la loro API pubblica ("funziona methodA ()?" e non "funziona questo metodo protetto?")
Il problema che ho è che i test per una nuova sottoclasse sono fondamentalmente un gioco da ragazzi: - I test sono tutti uguali in tutte le sottoclassi, cambiano solo il tipo di ritorno dei metodi (l'implementazione dello scheletro è generica) e le proprietà che controllo nella parte asserita del test. - Di solito le sottoclassi non hanno test specifici per loro
Mi piace il modo in cui i test si focalizzano sul risultato della sottoclasse e lo proteggono dal refactoring, ma il fatto che l'implementazione del test sia diventato solo "lavoro manuale" mi fa pensare che sto facendo qualcosa di sbagliato.
Questo problema è comune durante il test della gerarchia di classi? Come posso evitarlo?
ps: ho pensato di testare la classe skeleton, ma sembra anche strano creare una simulazione di una classe astratta per poterlo testare. E penso che qualsiasi refactoring sulla classe astratta che modifica un comportamento che non è previsto dalla sottoclasse non verrà notato come veloce. Il mio coraggio mi dice che testare la sottoclasse "nel suo insieme" è l'approccio preferito qui, ma per favore sentiti libero di dirmi che ho torto:)
ps2: ho cercato su Google e ho trovato molte domande sull'argomento. Uno di questi è questo che ha un'ottima risposta di Nigel Thorne, il mio caso sarebbe stato il suo "numero 1." Sarebbe grandioso, ma a questo punto non posso refactoring, quindi dovrei convivere con questo problema. Se potessi refactoring, avrei ciascuna sottoclasse come strategia. Sarebbe OK, ma testerei comunque la "classe principale" e testerò le strategie, ma non noterei alcun refactoring che interrompa l'integrazione tra la classe principale e le strategie.
ps3: ho trovato alcune risposte che dicono che "è accettabile" testare la classe astratta. Sono d'accordo che questo è accettabile, ma mi piacerebbe sapere qual è l'approccio preferito in questo caso (sto ancora iniziando con i test unitari)