Mam szkieletową implementację, jak w punkcie 18 z Effective Java ( tutaj rozszerzona dyskusja ). Jest to klasa abstrakcyjna, która udostępnia 2 metody publiczne methodA () i methodB (), które wywołują metody podklas w celu „uzupełnienia luk”, których nie mogę zdefiniować w sposób abstrakcyjny.
Najpierw opracowałem go, tworząc dla niego konkretną klasę i pisząc testy jednostkowe. Gdy przyszła druga klasa, byłem w stanie wyodrębnić typowe zachowanie, zaimplementować „brakujące luki” w drugiej klasie i był on gotowy (oczywiście testy jednostkowe zostały utworzone dla drugiej podklasy).
Czas mijał i teraz mam 4 podklasy, z których każda implementuje 3 krótkie chronione metody, które są bardzo specyficzne dla ich konkretnej implementacji, podczas gdy implementacja szkieletowa wykonuje całą ogólną pracę.
Mój problem polega na tym, że kiedy tworzę nową implementację, piszę testy od nowa:
- Czy podklasa wywołuje daną wymaganą metodę?
- Czy dana metoda ma przypisaną adnotację?
- Czy otrzymuję oczekiwane wyniki z metody A?
- Czy otrzymuję oczekiwane wyniki z metody B?
Zobacz zalety tego podejścia:
- Dokumentuje wymagania dotyczące podklasy poprzez testy
- Może szybko zawieść w przypadku problematycznego refaktoryzacji
- Przetestuj podklasę jako całość i za pomocą jej publicznego interfejsu API („czy metoda A () działa?”, A nie „czy ta chroniona metoda działa?”)
Problem, jaki mam, polega na tym, że testy nowej podklasy są w zasadzie nie wymagające: sprawdź część potwierdzającą testu. - Zazwyczaj podklasy nie mają specyficznych dla nich testów
Podoba mi się sposób, w jaki testy koncentrują się na wyniku samej podklasy i chronią ją przed refaktoryzacją, ale fakt, że wdrożenie testu stało się po prostu „pracą ręczną”, sprawia, że myślę, że robię coś złego.
Czy ten problem występuje często podczas testowania hierarchii klas? Jak mogę tego uniknąć?
ps: Myślałem o przetestowaniu klasy szkieletu, ale wydaje się również dziwne tworzenie makiety klasy abstrakcyjnej, aby móc ją przetestować. I myślę, że każde refaktoryzowanie klasy abstrakcyjnej, które zmienia zachowanie, którego nie oczekuje się od podklasy, nie zostanie zauważone tak szybko. Moje wnętrzności mówią mi, że testowanie podklasy „jako całości” jest tutaj preferowanym podejściem, ale nie wahaj się powiedzieć, że się mylę :)
ps2: Poszukałem go i znalazłem wiele pytań na ten temat. Jednym z nich jest ten, który ma świetną odpowiedź od Nigela Thorne'a, moja sprawa byłaby jego „numerem 1”. Byłoby świetnie, ale w tym momencie nie mogę refaktoryzować, więc musiałbym żyć z tym problemem. Gdybym mógł dokonać refaktoryzacji, miałbym każdą podklasę jako strategię. To by było OK, ale nadal testowałbym „klasę główną” i testował strategie, ale nie zauważyłem żadnego refaktoryzacji, który łamałby integrację między klasą główną a strategiami.
ps3: Znalazłem kilka odpowiedzi stwierdzających, że „dopuszczalne jest testowanie klasy abstrakcyjnej. Zgadzam się, że jest to do przyjęcia, ale chciałbym wiedzieć, jakie jest preferowane podejście w tym przypadku (wciąż zaczynam od testów jednostkowych)