Staramy się zaprojektować nasz system w taki sposób, aby był testowalny i w większości został opracowany przy użyciu TDD. Obecnie próbujemy rozwiązać następujący problem:
W różnych miejscach konieczne jest stosowanie metod statycznego pomocnika, takich jak ImageIO i URLEncoder (oba standardowe API Java) oraz różnych innych bibliotek, które składają się głównie z metod statycznych (takich jak biblioteki Apache Commons). Jednak niezwykle trudno jest przetestować metody wykorzystujące takie statyczne klasy pomocnicze.
Mam kilka pomysłów na rozwiązanie tego problemu:
- Użyj fałszywego frameworka, który potrafi drwić z klas statycznych (np. PowerMock). To może być najprostsze rozwiązanie, ale w jakiś sposób wydaje się, że trzeba się poddać.
- Utwórz natychmiastowe klasy opakowań wokół wszystkich tych narzędzi statycznych, aby można je było wstrzykiwać do klas, które ich używają. To brzmi jak stosunkowo czyste rozwiązanie, ale obawiam się, że skończymy z tworzeniem okropnej liczby tych klas opakowań.
- Wyodrębnij każde wywołanie tych statycznych klas pomocniczych do funkcji, którą można zastąpić, i przetestuj podklasę klasy, którą faktycznie chcę przetestować.
Ale ciągle myślę, że to musi być problem, z którym wiele osób musi się zmierzyć podczas TDD - więc muszą już być rozwiązania tego problemu.
Jaka jest najlepsza strategia umożliwiająca testowanie klas korzystających z tych statycznych pomocników?
źródło
Odpowiedzi:
(Obawiam się, że nie ma tu żadnych „oficjalnych” źródeł - to nie jest specyfikacja, jak dobrze testować. Tylko moje opinie, które, mam nadzieję, będą przydatne).
Gdy te metody statyczne reprezentują prawdziwe zależności, utwórz opakowania. Więc dla rzeczy takich jak:
... sensownie jest stworzyć interfejs.
Ale wielu metod w Apache Commons prawdopodobnie nie należy wyśmiewać / sfałszować. Na przykład weź metodę, aby połączyć listę ciągów, dodając przecinek między nimi. Wyśmiewanie ich nie ma sensu - po prostu pozwól statycznemu wywołaniu wykonać swoją normalną pracę. Nie chcesz ani nie musisz zastępować normalnego zachowania; nie masz do czynienia z zasobem zewnętrznym lub czymś, z czym trudno jest pracować, to tylko dane. Rezultat jest przewidywalny i i tak nigdy nie chciałbyś, aby był to coś innego niż to, co ci da.
Podejrzewam, że po usunięciu wszystkich wywołań statycznych, które tak naprawdę są wygodnymi metodami z przewidywalnymi, „czystymi” wynikami (takimi jak kodowanie base64 lub URL), a nie punktami wejścia w cały wielki bałagan zależności logicznych (jak HTTP), przekonasz się, że jest to całkowicie praktyczne robić właściwe rzeczy z prawdziwymi zależnościami.
źródło
Jest to zdecydowanie uparte zdanie / pytanie, ale za ile warto pomyślałem, że wrzucę moje dwa centy. Pod względem stylu TDD metoda 2 jest zdecydowanie podejściem, które podąża za nią do litery. Argumentem dla metody 2 jest to, że jeśli kiedykolwiek chciałbyś zastąpić implementację jednej z tych klas - powiedzmy
ImageIO
równoważnej biblioteki - możesz to zrobić, zachowując zaufanie do klas, które wykorzystują ten kod.Jednak, jak wspomniałeś, jeśli użyjesz wielu metod statycznych, to w końcu napiszesz dużo kodu opakowania. Na dłuższą metę może to nie być złe. Jeśli chodzi o łatwość konserwacji, istnieją na to argumenty. Osobiście wolałbym takie podejście.
Powiedziawszy to, PowerMock istnieje z jakiegoś powodu. Jest to dość dobrze znany problem polegający na tym, że testowanie przy użyciu metod statycznych jest bardzo bolesne, stąd powstanie PowerMock. Myślę, że musisz rozważyć swoje opcje pod kątem tego, ile pracy będzie wymagało obejście wszystkich klas pomocników w porównaniu z użyciem PowerMock. Nie sądzę, że korzystanie z PowerMock „rezygnuje” - po prostu czuję, że owijanie klas zapewnia większą elastyczność w dużym projekcie. Im więcej zamówień publicznych (interfejsów), tym czystsze może być oddzielenie zamiaru od realizacji.
źródło
Jako odniesienie dla wszystkich, którzy również mają do czynienia z tym problemem i natkną się na to pytanie, opiszę, w jaki sposób postanowiliśmy rozwiązać problem:
Zasadniczo podążamy ścieżką opisaną jako # 2 (klasy otoki dla narzędzi statycznych). Ale używamy ich tylko wtedy, gdy jest to zbyt skomplikowane, aby zapewnić narzędziu wymagane dane do uzyskania pożądanego wyniku (tj. Gdy absolutnie musimy kpić z metody).
Oznacza to, że nie musimy pisać opakowania dla prostego narzędzia, takiego jak Apache Commons
StringEscapeUtils
(ponieważ ciągi, których potrzebują, można łatwo podać) i nie używamy próbnych metod dla metod statycznych (jeśli uważamy, że może być czas, aby napisać klasa opakowania, a następnie wyśmiewaj się z instancji opakowania).źródło
Testowałbym te klasy za pomocą Groovy . Groovy można łatwo dodać do dowolnego projektu Java. Dzięki niemu możesz dość łatwo wyśmiewać metody statyczne. Zobacz na przykład Mocking Static Methods using Groovy .
źródło
Pracuję dla dużej firmy ubezpieczeniowej, a nasz kod źródłowy powiększa się do 400 MB czystych plików Java. Opracowujemy całą aplikację bez myślenia o TDD. Od stycznia tego roku rozpoczęliśmy testy junit dla każdego elementu.
Najlepszym rozwiązaniem w naszym dziale było użycie fałszywych obiektów w niektórych metodach JNI, które były niezawodne w systemie (napisane w C) i jako takie nie można dokładnie oszacować wyników za każdym razem w każdym systemie operacyjnym. Nie mieliśmy innej opcji niż użycie wyśmiewanych klas i konkretnych implementacji metod JNI specjalnie w celu przetestowania każdego modułu aplikacji dla każdego obsługiwanego systemu operacyjnego.
Ale to było naprawdę szybkie i do tej pory działało całkiem dobrze. Polecam - http://www.easymock.org/
źródło
Obiekty współdziałają ze sobą, aby osiągnąć cel, gdy obiekt jest trudny do przetestowania ze względu na środowisko (punkt końcowy usługi WWW, warstwa dao uzyskująca dostęp do bazy danych, kontrolery obsługujące parametry żądania HTTP) lub jeśli chcesz przetestować obiekt w izolacji, a następnie wyśmiewasz te obiekty.
konieczność wyśmiewania metod statycznych jest nieprzyjemnym zapachem, musisz zaprojektować swoją aplikację bardziej zorientowaną obiektowo, a metody statyczne użytkowe do testowania jednostkowego nie dodają dużej wartości do projektu, klasa opakowania jest dobrym podejściem w zależności od sytuacji, ale spróbuj aby przetestować te obiekty, które używają metod statycznych.
źródło
Czasami używam opcji 4
Coś takiego.
To, co podoba mi się w tym podejściu, polega na tym, że utrzymuje statyczne metody narzędzi, co wydaje mi się właściwe, gdy próbuję użyć klasy w całym kodzie.
źródło