Przeczytałem ten post o tym, jak przetestować metody prywatne. Zwykle ich nie testuję, ponieważ zawsze myślałem, że szybsze jest testowanie tylko metod publicznych, które będą wywoływane spoza obiektu. Czy testujesz prywatne metody? Czy zawsze powinienem je testować?
unit-testing
testing
language-agnostic
Patrick Desjardins
źródło
źródło
Odpowiedzi:
Nie testuję jednostkowo metod prywatnych. Metoda prywatna to szczegół implementacji, który powinien być ukryty dla użytkowników klasy. Testowanie prywatnych metod przerywa enkapsulację.
Jeśli stwierdzę, że prywatna metoda jest ogromna, złożona lub na tyle ważna, że wymaga własnych testów, po prostu umieszczam ją w innej klasie i udostępniam tam publicznie ( Method Object ). Następnie mogę łatwo przetestować metodę wcześniej prywatną, ale teraz publiczną, która teraz żyje w swojej własnej klasie.
źródło
Jaki jest cel testowania?
Większość dotychczasowych odpowiedzi mówi, że metody prywatne to szczegóły implementacji, które nie mają (a przynajmniej nie powinny) mieć znaczenia, o ile interfejs publiczny jest dobrze przetestowany i działa. Jest to absolutnie poprawne, jeśli jedynym celem testowania jest zagwarantowanie działania interfejsu publicznego .
Osobiście moim podstawowym zastosowaniem do testów kodu jest zapewnienie, aby przyszłe zmiany kodu nie powodowały problemów i pomoc w moich wysiłkach debugowania, jeśli tak się stanie. Uważam, że testowanie metod prywatnych tak dokładnie, jak interfejs publiczny (jeśli nie bardziej!) Wspiera ten cel.
Zastanów się: masz publiczną metodę A, która wywołuje metodę prywatną B. Zarówno A, jak i B korzystają z metody C. C ulega zmianie (być może przez ciebie, być może przez dostawcę), powodując, że A zaczyna nieudane testy. Czy nie byłoby przydatne posiadanie testów dla B, nawet jeśli są one prywatne, abyś wiedział, czy problem dotyczy użycia A przez C, B przez C, czy obu?
Testowanie metod prywatnych stanowi również wartość dodaną w przypadkach, w których testowe pokrycie interfejsu publicznego jest niepełne. Chociaż jest to sytuacja, której na ogół chcemy uniknąć, testowanie jednostek wydajności zależy zarówno od testów wykrywających błędy, jak i związanych z nimi kosztów rozwoju i utrzymania tych testów. W niektórych przypadkach korzyści ze 100% pokrycia testowego można uznać za niewystarczające, aby uzasadnić koszty tych testów, powodując luki w pokryciu testowym interfejsu publicznego. W takich przypadkach dobrze ukierunkowany test metody prywatnej może być bardzo skutecznym dodatkiem do bazy kodu.
źródło
testDoSomething()
lubtestDoSomethingPrivate()
. To sprawia, że test jest mniej wartościowy. . Oto więcej powodów, dla których warto przetestować prywatny stackoverflow.com/questions/34571/… :Zazwyczaj podążam za radą Dave'a Thomasa i Andy'ego Hunta w ich książce Pragmatic Unit Testing :
Ale czasami nie mogę się powstrzymać od testowania prywatnych metod, ponieważ daje mi to poczucie, że buduję całkowicie solidny program.
źródło
Czuję się zmuszony do testowania funkcji prywatnych, ponieważ coraz częściej stosuję się do jednego z naszych najnowszych zaleceń dotyczących kontroli jakości w naszym projekcie:
Teraz efektem ubocznym egzekwowania tej polityki jest to, że wiele moich bardzo dużych funkcji publicznych jest podzielonych na wiele bardziej ukierunkowanych, lepiej nazwanych funkcji prywatnych .
Funkcja publiczna wciąż istnieje (oczywiście), ale jest zasadniczo zredukowana do wszystkich tych prywatnych „podfunkcji”
To jest naprawdę fajne, ponieważ callstack jest teraz znacznie łatwiejszy do odczytania (zamiast błędu w dużej funkcji, mam błąd w podfunkcji z nazwą poprzednich funkcji w callstacku, aby pomóc mi zrozumieć „jak się tam dostałem”)
Jednak teraz wydaje się łatwiejsze testowanie jednostkowe tych funkcji prywatnych i pozostawienie testowania dużej funkcji publicznej jakimś testom „integracyjnym”, w którym należy zająć się scenariuszem.
Tylko moje 2 centy.
źródło
Tak, testuję funkcje prywatne, ponieważ chociaż są one testowane za pomocą metod publicznych, miło jest w TDD (Test Driven Design) przetestować najmniejszą część aplikacji. Ale funkcje prywatne nie są dostępne, gdy jesteś w klasie jednostek testowych. Oto, co robimy, aby przetestować nasze prywatne metody.
Dlaczego mamy prywatne metody?
Funkcje prywatne istnieją głównie w naszej klasie, ponieważ chcemy stworzyć czytelny kod w naszych metodach publicznych. Nie chcemy, aby użytkownik tej klasy wywoływał te metody bezpośrednio, ale za pomocą naszych metod publicznych. Ponadto nie chcemy zmieniać ich zachowania podczas rozszerzania klasy (w przypadku ochrony), dlatego jest to prywatna.
Kiedy kodujemy, używamy projektowania testowego (TDD). Oznacza to, że czasami natrafiamy na element prywatny, który chcemy przetestować. Funkcje prywatne nie są testowane w phpUnit, ponieważ nie możemy uzyskać do nich dostępu w klasie Test (są prywatne).
Uważamy, że tutaj są 3 rozwiązania:
1. Możesz przetestować swoich szeregowych za pomocą metod publicznych
Zalety
Niedogodności
2. Jeśli wartość prywatna jest tak ważna, być może jest to kod, aby utworzyć dla niej nową osobną klasę
Zalety
Niedogodności
3. Zmień modyfikator dostępu na (końcowy) chroniony
Zalety
Niedogodności
Przykład
Nasza jednostka testowa może teraz wywołać test_sleepWithSuspect, aby przetestować naszą dawną funkcję prywatną.
źródło
Nie lubię testować prywatnej funkcjonalności z kilku powodów. Są one następujące (są to główne punkty dla osób TLDR):
Wyjaśnię każdy z nich konkretnym przykładem. Okazuje się, że 2) i 3) są dość ściśle powiązane, więc ich przykład jest podobny, chociaż uważam je za osobne powody, dla których nie powinieneś testować metod prywatnych.
Są chwile, w których testowanie prywatnych metod jest odpowiednie, ważne jest, aby zdawać sobie sprawę z wyżej wymienionych wad. Omówię to później bardziej szczegółowo.
Zastanawiam się również, dlaczego TDD nie jest usprawiedliwieniem do testowania prywatnych metod na samym końcu.
Refaktoryzacja wyjścia ze złego projektu
Jednym z najczęstszych (anty) paternów, które widzę, jest to, co Michael Feathers nazywa klasą „Góry lodowej” (jeśli nie wiesz, kim jest Michael Feathers, idź kupić / przeczytaj jego książkę „Skutecznie współpracując ze Starszym Kodem”. osoba, o której warto wiedzieć, czy jesteś profesjonalnym inżynierem / programistą). Istnieją inne (anty) wzorce, które powodują pojawienie się tego problemu, ale jest to zdecydowanie najbardziej powszechny, z jakim się zetknąłem. Klasy „Góra lodowa” mają jedną metodę publiczną, a pozostałe są prywatne (dlatego kuszące jest przetestowanie metod prywatnych). Nazywa się to klasą „Góra lodowa”, ponieważ zwykle występuje samotna metoda publiczna, ale reszta funkcji jest ukryta pod wodą w postaci prywatnych metod.
Na przykład możesz przetestować
GetNextToken()
, wywołując go kolejno i sprawdzając, czy zwraca oczekiwany wynik. Funkcja taka jak ta gwarantuje test: takie zachowanie nie jest trywialne, szczególnie jeśli twoje reguły tokenizacji są złożone. Udawajmy, że to nie jest aż tak skomplikowane, a my chcemy po prostu wplatać tokeny oddzielone spacją. Więc piszesz test, może wygląda to tak (jakiś agnostyczny kod psuedo, mam nadzieję, że pomysł jest jasny):Cóż, to naprawdę ładnie wygląda. Chcemy mieć pewność, że utrzymamy to zachowanie podczas wprowadzania zmian. Ale
GetNextToken()
jest funkcją prywatną ! Nie możemy więc przetestować tego w ten sposób, ponieważ nawet się nie skompiluje (zakładając, że używamy języka, który faktycznie wymusza publiczny / prywatny, w przeciwieństwie do niektórych języków skryptowych, takich jak Python). Ale co ze zmianąRuleEvaluator
klasy, aby postępowała zgodnie z zasadą pojedynczej odpowiedzialności (zasada pojedynczej odpowiedzialności)? Na przykład wydaje się, że analizator składni, tokenizer i ewaluator są zablokowane w jednej klasie. Czy nie lepiej byłoby po prostu rozdzielić te obowiązki? Ponadto, jeśli utworzyszTokenizer
klasę, wówczas będą to metody publiczneHasMoreTokens()
iGetNextTokens()
.RuleEvaluator
Klasa mogłaby miećTokenizer
obiekt jako członek. Teraz możemy zachować taki sam test jak powyżej, z tym wyjątkiem, że testujemyTokenizer
klasę zamiastRuleEvaluator
klasy.Oto, jak może to wyglądać w UML:
Zauważ, że ten nowy projekt zwiększa modułowość, więc możesz potencjalnie ponownie użyć tych klas w innych częściach twojego systemu (zanim nie mogłeś, metody prywatne nie są z definicji wielokrotnego użytku). Jest to główna zaleta zepsucia RuleEvaluator wraz ze zwiększoną zrozumiałością / lokalizacją.
Test wyglądałby bardzo podobnie, tyle że faktycznie skompilowałby się tym razem, ponieważ
GetNextToken()
metoda jest teraz publicznie dostępna wTokenizer
klasie:Testowanie komponentów prywatnych za pomocą publicznego interfejsu i unikanie powielania testów
Nawet jeśli nie uważasz, że możesz podzielić swój problem na mniejszą liczbę komponentów modułowych (co możesz zrobić w 95% przypadków, jeśli tylko spróbujesz to zrobić), możesz po prostu przetestować funkcje prywatne za pośrednictwem publicznego interfejsu. Często członkowie prywatni nie są warci testowania, ponieważ będą testowani przez interfejs publiczny. Często widzę testy, które wyglądają bardzo podobnie, ale testują dwie różne funkcje / metody. Ostatecznie dzieje się tak, że gdy wymagania się zmieniają (i zawsze tak się dzieje), masz teraz 2 zepsute testy zamiast 1. A jeśli naprawdę przetestowałeś wszystkie swoje prywatne metody, możesz mieć więcej takich jak 10 zepsutych testów zamiast 1. W skrócie , testowanie funkcji prywatnych (przy użyciu
FRIEND_TEST
lub upublicznienie ich lub użycie refleksji), które w innym przypadku mogłyby zostać przetestowane przez interfejs publiczny, mogą spowodować powielenie testu . Naprawdę tego nie chcesz, ponieważ nic nie boli bardziej niż zestaw testów, który cię spowalnia. Ma skrócić czas opracowywania i koszty konserwacji! W przypadku testowania metod prywatnych, które w innym przypadku byłyby testowane za pomocą interfejsu publicznego, zestaw testów może równie dobrze zrobić coś przeciwnego i aktywnie zwiększyć koszty konserwacji i wydłużyć czas programowania. Kiedy upubliczniasz funkcję prywatną lub jeśli używasz czegoś takiegoFRIEND_TEST
i / lub refleksji, zwykle na dłuższą metę zwykle będziesz żałować.Rozważ następującą możliwą implementację
Tokenizer
klasy:Powiedzmy, że
SplitUpByDelimiter()
odpowiada za zwrócenie tablicy tak, aby każdy element w tablicy był tokenem. Co więcej, powiedzmy, żeGetNextToken()
jest to po prostu iterator tego wektora. Twój publiczny test może wyglądać następująco:Udawajmy, że mamy narzędzie, którego nazywa Michael Feather . To narzędzie pozwala dotykać części prywatnych innych osób. Przykład pochodzi
FRIEND_TEST
z googletestu lub refleksji, jeśli język go obsługuje.Powiedzmy teraz, że wymagania się zmieniają, a tokenizacja staje się znacznie bardziej złożona. Decydujesz, że prosty ogranicznik łańcucha nie wystarczy i potrzebujesz
Delimiter
klasy do obsługi zadania. Oczywiście, będziesz oczekiwać, że jeden test się zepsuje, ale ten ból nasila się, gdy testujesz funkcje prywatne.Kiedy testowanie metod prywatnych może być właściwe?
W oprogramowaniu nie ma „jednego rozmiaru dla wszystkich”. Czasami w porządku (i właściwie idealnym) jest „łamanie zasad”. Zdecydowanie opowiadam się za nie testowaniem prywatnej funkcjonalności, kiedy możesz. Są dwie główne sytuacje, kiedy myślę, że jest w porządku:
Pracowałem intensywnie ze starszymi systemami (dlatego jestem wielkim fanem Michaela Feathersa) i mogę śmiało powiedzieć, że czasami najbezpieczniej jest po prostu przetestować prywatną funkcjonalność. Może to być szczególnie pomocne przy wprowadzaniu „testów charakteryzacyjnych” do linii podstawowej.
Spieszysz się i musisz zrobić najszybszą możliwą rzecz tu i teraz. Na dłuższą metę nie chcesz testować prywatnych metod. Powiem jednak, że refaktoryzacja zazwyczaj zajmuje trochę czasu, aby rozwiązać problemy projektowe. A czasem musisz wysłać za tydzień. W porządku: zrób szybki i brudny test i przetestuj prywatne metody za pomocą narzędzia do omijania, jeśli uważasz, że jest to najszybszy i najbardziej niezawodny sposób na wykonanie zadania. Ale zrozumcie, że to, co zrobiliście, nie było optymalne na dłuższą metę, i proszę rozważyć powrót do tego (lub, jeśli zostało zapomniane, ale zobaczycie to później, naprawcie to).
Prawdopodobnie są inne sytuacje, w których jest w porządku. Jeśli uważasz, że to w porządku i masz dobre uzasadnienie, zrób to. Nikt cię nie powstrzymuje. Pamiętaj tylko o potencjalnych kosztach.
Wymówka TDD
Nawiasem mówiąc, naprawdę nie lubię ludzi używających TDD jako wymówki do testowania prywatnych metod. Ćwiczę TDD i nie sądzę, żeby TDD zmusiło cię do tego. Możesz najpierw napisać test (dla interfejsu publicznego), a następnie napisać kod, aby spełnić ten interfejs. Czasami piszę test interfejsu publicznego i spełnię go, pisząc jedną lub dwie mniejsze metody prywatne (ale nie testuję metod prywatnych bezpośrednio, ale wiem, że działają lub mój test publiczny nie powiedzie się ). Jeśli będę musiał przetestować przypadki tej prywatnej metody, napiszę całą masę testów, które trafią je za pośrednictwem mojego publicznego interfejsu.Jeśli nie możesz dowiedzieć się, jak trafić na skrajne skrzynie, jest to mocny znak, że musisz przeforsować małe komponenty za pomocą własnych metod publicznych. To znak, że funkcje prywatne robisz za dużo i poza zakresem klasy .
Czasami też zdarza mi się, że piszę test, który jest w tej chwili zbyt duży, by go przeżuć, i dlatego myślę: „eh wrócę do tego testu później, gdy będę miał więcej interfejsu API do pracy” (I Skomentuję to i zachowam w pamięci). W tym miejscu wielu deweloperów, których spotkałem, zacznie pisać testy ich prywatnej funkcjonalności, używając TDD jako kozła ofiarnego. Mówią „och, no cóż, potrzebuję innego testu, ale aby napisać ten test, będę potrzebować tych prywatnych metod. Dlatego, ponieważ nie mogę napisać żadnego kodu produkcyjnego bez napisania testu, muszę napisać test dla metody prywatnej ”. Ale to, co naprawdę muszą zrobić, to przefakturowanie na mniejsze komponenty wielokrotnego użytku zamiast dodawania / testowania szeregu prywatnych metod do ich obecnej klasy.
Uwaga:
Niedawno odpowiedziałem na podobne pytanie dotyczące testowania metod prywatnych za pomocą GoogleTest . Przeważnie zmodyfikowałem tę odpowiedź, aby była bardziej niezależna od języka.
PS Oto odpowiedni wykład na temat zajęć z góry lodowej i narzędzi do omijania autorstwa Michaela Feathersa: https://www.youtube.com/watch?v=4cVZvoFGJTU
źródło
_
, oznacza to „hej, to jest„ prywatny ”. Możesz go użyć, ale pełne ujawnienie, nie został zaprojektowany do ponownego użycia i powinieneś go użyć tylko, jeśli naprawdę wiesz co robisz ". Możesz zastosować to samo podejście w dowolnym języku: upublicznij tych członków, ale oznacz ich wiodącym_
. A może te funkcje naprawdę powinny być prywatne i po prostu przetestowane za pomocą publicznego interfejsu (więcej informacji znajduje się w odpowiedzi). To przypadek po przypadku, brak ogólnej zasadyMyślę, że najlepiej jest po prostu przetestować publiczny interfejs obiektu. Z punktu widzenia świata zewnętrznego liczy się tylko zachowanie interfejsu publicznego i do tego powinny być kierowane testy jednostkowe.
Gdy masz już napisane solidne testy jednostkowe dla obiektu, nie musisz wracać i zmieniać tych testów tylko dlatego, że zmieniła się implementacja interfejsu. W tej sytuacji zrujnowałeś spójność testów jednostkowych.
źródło
Jeśli twoja metoda prywatna nie jest testowana przez wywołanie metod publicznych, to co ona robi? Mówię prywatnie nie chroniony lub przyjaciel.
źródło
Jeśli metoda prywatna jest dobrze zdefiniowana (tj. Ma funkcję, która jest testowalna i nie ma zmieniać się w czasie), to tak. Testuję wszystko, co da się przetestować tam, gdzie ma to sens.
Na przykład biblioteka szyfrująca może ukrywać fakt, że wykonuje szyfrowanie blokowe za pomocą prywatnej metody, która szyfruje tylko 8 bajtów naraz. Napisałbym do tego test jednostkowy - nie ma się to zmienić, nawet jeśli jest ukryte, a jeśli się zepsuje (na przykład z powodu przyszłych ulepszeń wydajności), chcę wiedzieć, że zepsuła się prywatna funkcja, nie tylko zepsuła się jedna z funkcji publicznych.
Przyspiesza późniejsze debugowanie.
-Adam
źródło
Jeśli rozwijasz się pod kontrolą testową (TDD), przetestujesz swoje prywatne metody.
źródło
Nie jestem ekspertem w tej dziedzinie, ale testy jednostkowe powinny testować zachowanie, a nie implementację. Metody prywatne są ściśle częścią wdrożenia, więc IMHO nie powinno być testowane.
źródło
Testujemy metody prywatne na podstawie wnioskowania, co oznacza, że szukamy całkowitego pokrycia testu klasy co najmniej 95%, ale nasze testy wymagają jedynie metod publicznych lub wewnętrznych. Aby uzyskać zasięg, musimy wykonać wiele połączeń z podmiotami publicznymi / wewnętrznymi w zależności od różnych możliwych scenariuszy. To sprawia, że nasze testy są bardziej skupione na celu testowanego kodu.
Odpowiedź Trumpiego na post, który podałeś, jest najlepsza.
źródło
Testy jednostkowe, jak sądzę, służą do testowania metod publicznych. Twoje metody publiczne używają metod prywatnych, więc pośrednio są one również testowane.
źródło
Długo zastanawiałem się nad tym problemem, szczególnie próbując swoich sił w TDD.
Natknąłem się na dwa posty, które moim zdaniem wystarczająco dokładnie rozwiązują ten problem w przypadku TDD.
W podsumowaniu:
W przypadku korzystania z technik programowania (projektowania) opartego na testach, prywatne metody powinny powstać tylko podczas procesu przefaktoryzowania już działającego i przetestowanego kodu.
Ze względu na naturę procesu każda prosta funkcja implementacji wyodrębniona z dokładnie przetestowanej funkcji będzie autotestem (tj. Zasięgiem testów pośrednich).
Wydaje mi się wystarczająco jasne, że na początku kodowania większość metod będzie funkcjami wyższego poziomu, ponieważ zawierają w sobie / opisują projekt.
Dlatego te metody będą dostępne publicznie, a ich testowanie będzie dość łatwe.
Prywatne metody pojawią się później, gdy wszystko będzie działało dobrze, a my zajmiemy się faktoringiem ze względu na czytelność i czystość .
źródło
Jak wspomniano powyżej: „Jeśli nie przetestujesz swoich prywatnych metod, skąd wiesz, że się nie złamią?”
To jest poważny problem. Jednym z głównych punktów testów jednostkowych jest wiedzieć, gdzie, kiedy i jak coś się zepsuło jak najszybciej. W ten sposób zmniejsza się znaczna ilość prac rozwojowych i zapewniania jakości. Jeśli wszystko, co jest testowane, to opinia publiczna, to nie masz uczciwego opisu i opisu elementów wewnętrznych klasy.
Znalazłem jeden z najlepszych sposobów, aby to zrobić, po prostu dodaj odwołanie do testu do projektu i umieść testy w klasie równoległej do metod prywatnych. Wprowadź odpowiednią logikę kompilacji, aby testy nie były wbudowane w końcowy projekt.
Następnie masz wszystkie zalety przetestowania tych metod i możesz znaleźć problemy w ciągu kilku sekund w stosunku do minut lub godzin.
Podsumowując, tak, jednostka przetestuj swoje prywatne metody.
źródło
Nie powinieneś . Jeśli twoje prywatne metody mają wystarczającą złożoność, którą należy przetestować, powinieneś umieścić je w innej klasie. Zachowaj wysoką spójność , klasa powinna mieć tylko jeden cel. Klasowy interfejs publiczny powinien wystarczyć.
źródło
Jeśli nie przetestujesz swoich prywatnych metod, skąd wiesz, że się nie złamią?
źródło
To oczywiście zależy od języka. W przeszłości z c ++ zadeklarowałem klasę testową jako klasę zaprzyjaźnioną. Niestety wymaga to, aby Twój kod produkcyjny wiedział o klasie testowej.
źródło
Rozumiem punkt widzenia, w którym prywatne metody są uważane za szczegóły implementacji, a następnie nie muszą być testowane. I trzymałbym się tej zasady, gdybyśmy musieli rozwijać się poza obiektem. Ale my, czy jesteśmy rodzajem ograniczonych programistów, którzy rozwijają się tylko poza obiektami, nazywając tylko swoje metody publiczne? Czy też faktycznie rozwijamy również ten obiekt? Ponieważ nie jesteśmy zobowiązani do programowania obiektów zewnętrznych, prawdopodobnie będziemy musieli wywołać te prywatne metody w nowe, opracowywane przez nas metody publiczne. Czy nie byłoby wspaniale wiedzieć, że prywatna metoda jest odporna na wszelkie przeciwności?
Wiem, że niektórzy ludzie mogą odpowiedzieć, że jeśli opracowujemy inną metodę publiczną w tym obiekcie, to ten powinien zostać przetestowany i to wszystko (prywatna metoda mogłaby żyć bez testu). Ale dotyczy to również wszelkich publicznych metod obiektu: podczas opracowywania aplikacji internetowej wszystkie publiczne metody obiektu są wywoływane z metod kontrolerów, a zatem mogą być uważane za szczegóły implementacji dla kontrolerów.
Dlaczego więc przeprowadzamy testy jednostkowe obiektów? Ponieważ jest to naprawdę trudne, nie można nie mieć pewności, że testujemy metody kontrolerów przy użyciu odpowiednich danych wejściowych, które uruchomią wszystkie gałęzie kodu źródłowego. Innymi słowy, im wyżej znajdujemy się na stosie, tym trudniej jest przetestować wszystkie zachowania. Podobnie jest w przypadku metod prywatnych.
Dla mnie granica między metodami prywatnymi i publicznymi jest psychologicznym kryterium, jeśli chodzi o testy. Najważniejsze dla mnie kryteria to:
źródło
Jeśli stwierdzę, że prywatna metoda jest ogromna, złożona lub wystarczająco ważna, aby wymagać własnych testów, po prostu umieszczam ją w innej klasie i udostępniam tam publicznie (Method Object). Następnie mogę łatwo przetestować wcześniej prywatną, ale teraz publiczną metodę, która teraz żyje w swojej własnej klasie.
źródło
Nigdy nie rozumiem pojęcia testu jednostkowego, ale teraz wiem, jaki jest jego cel.
Test jednostkowy nie jest pełnym testem . Nie zastępuje to kontroli jakości ani testu ręcznego. Koncepcja TDD w tym aspekcie jest błędna, ponieważ nie można przetestować wszystkiego, w tym metod prywatnych, ale także metod wykorzystujących zasoby (zwłaszcza zasoby, nad którymi nie mamy kontroli). TDD opiera całą swoją jakość na czymś, czego nie można osiągnąć.
Test jednostkowy jest raczej testem przestawnym Zaznaczasz jakiś dowolny punkt przestawny, a wynik przestawienia powinien pozostać taki sam.
źródło
Publiczny vs. prywatny nie jest przydatnym rozróżnieniem dla tego, do czego api mogą zadzwonić z twoich testów, ani metoda vs. klasa. Większość testowalnych jednostek jest widoczna w jednym kontekście, ale ukryta w innych.
Liczy się ochrona i koszty. Musisz zminimalizować koszty przy jednoczesnym osiągnięciu celów pokrycia twojego projektu (linia, gałąź, ścieżka, blok, metoda, klasa, klasa równoważności, przypadek użycia ... cokolwiek decyduje zespół).
Dlatego używaj narzędzi, aby zapewnić zasięg, i zaprojektuj testy tak, aby powodowały jak najniższe koszty (krótko- i długoterminowe ).
Nie rób testów droższych niż to konieczne. Jeśli testowanie publicznych punktów wejścia jest najtańsze, zrób to. Jeśli testowanie metod prywatnych jest najtańsze, zrób to.
W miarę zdobywania doświadczenia możesz lepiej przewidywać, kiedy warto dokonać refaktoryzacji, aby uniknąć długoterminowych kosztów utrzymania testów.
źródło
Jeśli metoda jest wystarczająco znacząca / wystarczająco złożona, zwykle sprawię, że będzie „chroniona” i przetestuję ją. Niektóre metody pozostaną prywatne i przetestowane pośrednio jako część testów jednostkowych dla metod publicznych / chronionych.
źródło
Widzę, że wiele osób ma takie samo zdanie: test na poziomie publicznym. ale czy nie to robi nasz zespół ds. kontroli jakości? Testują wejście i oczekiwane wyjście. Jeśli jako programiści testujemy tylko metody publiczne, po prostu ponawiamy zadanie kontroli jakości i nie dodajemy żadnej wartości poprzez „testowanie jednostkowe”.
źródło
Odpowiedź na „Czy powinienem przetestować metody prywatne?” jest czasami". Zazwyczaj powinieneś testować na interfejsie swoich klas.
Oto przykład:
W
RefactoredThing
masz teraz 5 testów, z których 2 trzeba było zaktualizować do refactoring, ale funkcjonalność Twojego obiektu naprawdę nie uległa zmianie. Powiedzmy, że rzeczy są bardziej skomplikowane i masz jakąś metodę, która określa kolejność danych wyjściowych, na przykład:To nie powinno być uruchamiane przez zewnętrznego użytkownika, ale twoja klasa enkapsulacji może być zbyt ciężka, aby uruchamiać w niej tyle logiki w kółko. W takim przypadku może wolisz wyodrębnić to do osobnej klasy, dać tej klasie interfejs i przetestować ją.
I na koniec, powiedzmy, że twój główny obiekt jest bardzo ciężki, a metoda jest dość mała i naprawdę musisz upewnić się, że dane wyjściowe są prawidłowe. Myślisz: „Muszę przetestować tę prywatną metodę!”. Czy zdajesz sobie sprawę, że możesz uczynić obiekt lżejszym, przekazując część ciężkiej pracy jako parametr inicjalizacji? Następnie możesz podać coś lżejszego i przetestować na tym.
źródło
Nie. Dlaczego nie powinieneś testować prywatnych metod ? a ponadto popularna frameworka mockingowa, taka jak Mockito, nie zapewnia wsparcia dla testowania metod prywatnych.
źródło
Jednym z głównych punktów jest
Jeśli przeprowadzamy testy w celu zapewnienia poprawności logiki, a logika prywatna przenosi logikę, powinniśmy ją przetestować. Czyż nie Dlaczego więc to pomijamy?
Pisanie testów w oparciu o widoczność metod jest całkowicie nieistotnym pomysłem.
Odwrotnie
Z drugiej strony, wywoływanie metody prywatnej poza oryginalną klasą jest głównym problemem. Istnieją również ograniczenia wyśmiewania prywatnej metody w niektórych narzędziach wyśmiewania. (Np .: Mockito )
Chociaż istnieją narzędzia takie jak Power Mock, które to obsługują, jest to niebezpieczna operacja. Powodem jest zhakowanie JVM, aby to osiągnąć.
Jednym z obejść, które można zrobić, jest (jeśli chcesz napisać przypadki testowe dla metod prywatnych)
Zadeklaruj te prywatne metody jako chronione . Ale może to nie być wygodne w kilku sytuacjach.
źródło
Nie chodzi tylko o publiczne lub prywatne metody lub funkcje, ale o szczegóły implementacji. Funkcje prywatne to tylko jeden aspekt szczegółów implementacji.
Testowanie jednostkowe to w końcu podejście polegające na testowaniu białych skrzynek. Na przykład ten, kto korzysta z analizy pokrycia w celu zidentyfikowania części kodu, które do tej pory były zaniedbywane w testowaniu, zapozna się ze szczegółami implementacji.
A) Tak, powinieneś testować szczegóły implementacji:
Pomyśl o funkcji sortowania, która ze względu na wydajność używa prywatnej implementacji BubbleSort, jeśli jest do 10 elementów, oraz prywatnej implementacji innego podejścia sortowania (powiedzmy, heapsort), jeśli jest więcej niż 10 elementów. Publiczny interfejs API to funkcja sortowania. Jednak Twój zestaw testów lepiej wykorzystuje wiedzę, że w rzeczywistości są używane dwa algorytmy sortowania.
W tym przykładzie z pewnością można wykonać testy publicznego interfejsu API. Wymagałoby to jednak posiadania wielu przypadków testowych, które wykonują funkcję sortowania z więcej niż 10 elementami, tak aby algorytm heapsortowy był wystarczająco dobrze przetestowany. Samo istnienie takich przypadków testowych wskazuje, że zestaw testów jest powiązany ze szczegółami implementacji funkcji.
Jeśli szczegóły implementacji funkcji sortowania zmienią się, być może w ten sposób, że granica między dwoma algorytmami sortowania zostanie przesunięta lub że heapsort zostanie zastąpiony przez scalesort lub cokolwiek innego: istniejące testy będą nadal działać. Ich wartość jest jednak wątpliwa i prawdopodobnie trzeba je przerobić, aby lepiej przetestować zmienioną funkcję sortowania. Innymi słowy, konieczne będą prace konserwacyjne pomimo faktu, że testy odbywały się na publicznym interfejsie API.
B) Jak przetestować szczegóły implementacji
Jednym z powodów, dla których wiele osób twierdzi, że nie należy testować funkcji prywatnych ani szczegółów implementacji, jest to, że bardziej prawdopodobne jest, że szczegóły implementacji ulegną zmianie. To wyższe prawdopodobieństwo zmiany jest przynajmniej jednym z powodów ukrywania szczegółów implementacji za interfejsami.
Załóżmy teraz, że implementacja za interfejsem zawiera większe części prywatne, dla których indywidualne testy interfejsu wewnętrznego mogą być opcją. Niektórzy twierdzą, że te części nie powinny być testowane, gdy są prywatne, należy je zamienić w coś publicznego. Po upublicznieniu testowanie jednostkowe tego kodu byłoby w porządku.
Jest to interesujące: chociaż interfejs był wewnętrzny, prawdopodobnie mógł się zmienić, ponieważ był szczegółem implementacji. Biorąc ten sam interfejs, upubliczniając, dokonuje on pewnej magicznej transformacji, a mianowicie przekształca go w interfejs, który prawdopodobnie nie ulegnie zmianie. Oczywiście w tej argumentacji jest pewna wada.
Niemniej jednak kryje się za tym pewna prawda: podczas testowania szczegółów implementacji, w szczególności przy użyciu interfejsów wewnętrznych, należy dążyć do korzystania z interfejsów, które prawdopodobnie pozostaną stabilne. To, czy dany interfejs będzie prawdopodobnie stabilny, nie jest jednak rozstrzygalne na podstawie tego, czy jest on publiczny, czy prywatny. W projektach ze świata, nad którymi pracuję od jakiegoś czasu, interfejsy publiczne również dość często się zmieniają, a wiele prywatnych interfejsów pozostaje niezmienionych od wieków.
Nadal dobrą zasadą jest używanie „drzwi frontowych jako pierwszych” (patrz http://xunitpatterns.com/Principles%20of%20Test%20Automation.html ). Pamiętaj jednak, że nazywa się to „najpierw drzwiami wejściowymi”, a nie „tylko drzwiami wejściowymi”.
C) Podsumowanie
Przetestuj również szczegóły implementacji. Preferuj testowanie na stabilnych interfejsach (publicznych lub prywatnych). Jeśli szczegóły implementacji ulegną zmianie, należy również zweryfikować testy publicznego interfejsu API. Przekształcenie czegoś prywatnego w publiczne nie zmienia magicznie jego stabilności.
źródło
Tak, w miarę możliwości powinieneś przetestować prywatne metody. Dlaczego? Aby uniknąć niepotrzebnej eksplozji w przestrzeni stanów przypadków testowych, które ostatecznie ostatecznie niejawnie testują wielokrotnie te same funkcje prywatne na tych samych danych wejściowych. Wytłumaczmy dlaczego na przykładzie.
Rozważ następujący lekko wymyślony przykład. Załóżmy, że chcemy publicznie udostępnić funkcję, która przyjmuje 3 liczby całkowite i zwraca wartość true tylko wtedy, gdy te 3 liczby całkowite są liczbą pierwszą. Możemy to zaimplementować w następujący sposób:
Teraz, gdybyśmy przyjęli ścisłe podejście, że tylko funkcje publiczne powinny być testowane, moglibyśmy tylko testować,
allPrime
a nieisPrime
lubandAll
.Jako tester, możemy być zainteresowany w pięciu możliwości każdego argumentu:
< 0
,= 0
,= 1
,prime > 1
,not prime > 1
. Ale żeby być dokładnym, musielibyśmy także zobaczyć, jak każda kombinacja argumentów gra razem. To5*5*5
znaczy = 125 przypadków testowych, które musielibyśmy dokładnie przetestować tę funkcję, zgodnie z naszymi intuicjami.Z drugiej strony, gdybyśmy mogli przetestować funkcje prywatne, moglibyśmy objąć tyle samo terenu przy mniejszej liczbie przypadków testowych. Potrzebowalibyśmy tylko 5 przypadków testowych, aby przetestować
isPrime
na tym samym poziomie, co nasza poprzednia intuicja. A zgodnie z hipotezą małego zakresu zaproponowaną przez Daniela Jacksona musielibyśmy przetestowaćandAll
funkcję tylko na małej długości, np. 3 lub 4. To byłoby co najwyżej 16 testów. Łącznie 21 testów. Zamiast 125. Oczywiście prawdopodobnie chcielibyśmy przeprowadzić kilka testówallPrime
, ale nie czulibyśmy się zobowiązani do wyczerpującego omówienia wszystkich 125 kombinacji scenariuszy wejściowych, o których mówiliśmy, że nam zależy. Tylko kilka szczęśliwych ścieżek.Z pewnością wymyślony przykład, ale był konieczny do jasnej demonstracji. A wzór rozciąga się na prawdziwe oprogramowanie. Funkcje prywatne są zwykle elementami składowymi najniższego poziomu, a zatem są często łączone razem w celu uzyskania logiki wyższego poziomu. Oznacza to, że na wyższych poziomach mamy więcej powtórzeń rzeczy z niższych poziomów ze względu na różne kombinacje.
źródło
isPrime
są naprawdę niezależne, więc testowanie każdej kombinacji na ślepo jest dość bezcelowe. Po drugie, oznaczenie czystej funkcji o nazwieisPrime
private narusza tak wiele reguł projektowania, że nawet nie wiem od czego zacząć.isPrime
powinna bardzo wyraźnie być funkcją publiczną. Biorąc to pod uwagę, rozumiem, co mówisz, bez względu na ten bardzo słaby przykład. Jest to jednak oparte na założeniu, że chcesz przeprowadzać testy kombinacji, gdy w prawdziwych systemach oprogramowania rzadko jest to dobry pomysł.Możesz także ustawić metodę pakietu na prywatną, tzn. Domyślną, i powinieneś być w stanie przetestować ją jednostkowo, chyba że jest wymagana prywatność.
źródło