Pracuję nad tym, aby moje klasy mogły być testowane jednostkowo przy użyciu wstrzykiwania zależności. Ale niektóre z tych klas mają wielu klientów i nie jestem jeszcze gotowy przefakturować ich wszystkich, aby zacząć przekazywać zależności. Więc staram się to robić stopniowo; zachowując na razie domyślne zależności, ale pozwalając na ich zastąpienie w celu przetestowania.
Jednym z moich podejść jest przeniesienie wszystkich „nowych” wywołań do własnych metod, np .:
public MyObject createMyObject(args) {
return new MyObject(args);
}
Następnie w moich testach jednostkowych mogę po prostu podklasować tę klasę i zastąpić funkcje tworzenia, aby zamiast tego tworzyły fałszywe obiekty.
Czy to dobre podejście? Czy są jakieś wady?
Mówiąc bardziej ogólnie, czy dobrze jest mieć sztywno zakodowane zależności, o ile można je zastąpić do testowania? Wiem, że preferowanym podejściem jest wyraźne wymaganie ich od konstruktora i chciałbym w końcu tam dotrzeć. Ale zastanawiam się, czy to dobry pierwszy krok.
Jedna wada, która właśnie mi się przydarzyła: jeśli masz prawdziwe podklasy, które musisz przetestować, nie możesz ponownie użyć podklasy testowej, którą napisałeś dla klasy nadrzędnej. Będziesz musiał utworzyć podklasę testową dla każdej prawdziwej podklasy i będzie musiał zastąpić te same funkcje tworzenia.
Odpowiedzi:
To dobre podejście na początek. Pamiętaj, że najważniejsze jest objęcie istniejącego kodu testami jednostkowymi; po przeprowadzeniu testów możesz dowolnie refaktoryzować, aby jeszcze bardziej ulepszyć swój projekt.
Tak więc początkowo nie chodzi o to, aby projekt był elegancki i błyszczący - wystarczyło przetestować jednostkę kodu przy najmniej ryzykownych zmianach . Bez testów jednostkowych musisz być bardzo konserwatywny i ostrożny, aby uniknąć złamania kodu. Te początkowe zmiany mogą nawet sprawić, że kod będzie wyglądał bardziej niezgrabnie lub brzydko w niektórych przypadkach - ale jeśli pozwolą ci napisać pierwsze testy jednostkowe, w końcu będziesz w stanie zreformować się w kierunku idealnego projektu, który masz na myśli.
Podstawową pracą, którą należy przeczytać na ten temat, jest Efektywna praca ze starszym kodeksem . Opisuje sztuczkę pokazaną powyżej i wiele, wiele innych, w kilku językach.
źródło
Guice-ludzie zalecają używanie
dla wszystkich właściwości zamiast dodawania @Inject do ich definicji. Umożliwi to traktowanie ich jak zwykłych ziaren, co można zrobić
new
podczas testowania (i ręcznego ustawiania właściwości) i @Inject w produkcji.źródło
Kiedy mam do czynienia z tego rodzaju problemem, zidentyfikuję każdą zależność od mojej klasy do przetestowania i utworzę chronionego konstruktora, który pozwoli mi je przekazać. Jest to faktycznie to samo, co utworzenie ustawienia dla każdego, ale wolę deklarowanie zależności w moich konstruktorach, aby nie zapomnieć o tworzeniu ich w przyszłości.
Tak więc moja nowa klasa do testowania jednostkowego będzie miała 2 konstruktory:
źródło
Możesz rozważyć użycie wyrażenia „getter tworzy”, dopóki nie będziesz w stanie użyć wstrzykniętej zależności.
Na przykład,
Umożliwi to wewnętrzną refaktoryzację, dzięki czemu będzie można odwoływać się do mojego obiektu przez getter. Nigdy nie musisz dzwonić
new
. W przyszłości, gdy wszyscy klienci zostaną skonfigurowani tak, aby zezwalać na wstrzykiwanie zależności, wystarczy usunąć kod tworzenia w jednym miejscu - getterze. Seter pozwoli ci wstrzykiwać fałszywe obiekty zgodnie z wymaganiami.Powyższy kod jest tylko przykładem i bezpośrednio ujawnia stan wewnętrzny. Powinieneś dokładnie rozważyć, czy to podejście jest odpowiednie dla twojej bazy kodów.
Polecam również przeczytanie „ Skutecznej pracy ze starszym kodem ”, która zawiera wiele przydatnych wskazówek, które pozwolą odnieść sukces w dużym refaktoryzacji.
źródło