Czy mam testować metody prywatne czy tylko publiczne?

Przeczytałem Ten post o tym, jak testować prywatne metody. Zwykle ich nie testuję, ponieważ zawsze uważałem, że szybciej jest testować tylko publiczne metody, które będą wywoływane spoza obiektu. Testujesz prywatne metody? Czy zawsze mam je testować?

Author: Community, 2008-09-19

26 answers

Nie testuję metod prywatnych. Metoda prywatna jest szczegółem implementacji, który powinien być ukryty dla użytkowników klasy. Testowanie prywatnych metod przerywa enkapsulację.

Jeśli okaże się, ż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 tam upubliczniam (Method Object ). Następnie mogę łatwo przetestować wcześniej-prywatną-ale-teraz-publiczną metodę, która teraz żyje na własnej klasie.

 281
Author: jop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-30 15:26:17

Jaki jest cel testowania?

Większość odpowiedzi mówi, że metody prywatne są szczegółami implementacji, które nie mają (a przynajmniej nie powinny) znaczenia, dopóki publiczny interfejs jest dobrze przetestowany i działa. Jest to absolutnie poprawne , jeśli jedynym celem testowania jest zagwarantowanie, że publiczny interfejs działa .

Osobiście, moim głównym zastosowaniem w testach kodu jest upewnienie się, że przyszłe zmiany w kodzie nie powodują problemów i pomoc w moim debugowanie wysiłków, jeśli tak się stanie. Uważam, że testowanie prywatnych metod jest tak samo dokładne jak publiczny interfejs (jeśli nie bardziej!).

Rozważ: masz publiczną metodę A, która wywołuje prywatną metodę B. A i B używają metody C. C jest zmieniana (być może przez Ciebie, być może przez dostawcę), powodując, że A zaczyna oblać testy. Czy nie przydałoby się też mieć testów na B, mimo że są prywatne, żeby wiedzieć czy problem leży w używaniu C przez A, a przez B C, czy jedno i drugie?

Testowanie prywatnych metod również dodaje wartość w przypadkach, gdy zakres testowy interfejsu publicznego jest niekompletny. Chociaż jest to sytuacja, której zazwyczaj chcemy uniknąć, testy jednostkowe wydajności zależą 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 wynikające ze 100% pokrycia testów mogą zostać uznane za niewystarczające, aby uzasadnić koszty tych testów, powodując luki w pokryciu testów interfejsu publicznego. W w takich przypadkach dobrze ukierunkowany test prywatnej metody może być bardzo skutecznym dodatkiem do bazy kodu.

 257
Author: Dave Sherohman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-06 06:48:29

Mam tendencję do podążania za radami Dave 'a Thomasa i Andy' ego Hunta w ich książcePragmatic Unit Testing:

Ogólnie rzecz biorąc, nie chcesz łamać żadnej enkapsulacji ze względu na testowanie (lub jak mawiała mama: "nie ujawniaj swoich privatów!"). Najbardziej czasu, powinieneś być w stanie przetestować klasę, ćwicząc jej metody publiczne. Jeśli istnieje znaczna funkcjonalność, która jest ukryta za dostępem prywatnym lub chronionym, może to być znak ostrzegawczy, że jest kolejna klasa walczy o wyjście.

Ale czasami nie mogę powstrzymać się od testowania prywatnych metod, ponieważ daje mi to poczucie pewności, że buduję CAŁKOWICIE solidny program.

 133
Author: Rosellyne Thompson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-07 03:38:42

Czuję się jakby zmuszony do testowania prywatnych funkcji, ponieważ coraz częściej śledzę jedną z naszych najnowszych rekomendacji QA w naszym projekcie:

Nie więcej niż 10 W złożoności cyklomatycznej na funkcję.

Teraz efektem ubocznym egzekwowania tej polityki jest to, że wiele z moich bardzo dużych publicznych funkcji zostaje podzielonych na wiele bardziej skoncentrowanych, lepiej nazwanych prywatnych funkcji.
Funkcja publiczna nadal istnieje (oczywiście) , ale jest zasadniczo zredukowana do nazywa wszystkie te prywatne 'podfunkcje'

To naprawdę fajne, ponieważ callstack jest teraz dużo łatwiejszy do odczytania (zamiast błędu w dużej funkcji, mam błąd w pod-Pod-funkcji z nazwą poprzednich funkcji w callstack, aby pomóc mi zrozumieć "jak się tam znalazłem")

Jednak teraz wydaje się łatwiej testować bezpośrednio te prywatne funkcje i pozostawić testowanie dużej funkcji publicznej do pewnego rodzaju "testu integracyjnego", gdzie należy zająć się scenariuszem.

Tylko moje 2 centy.
 56
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 20:09:53

Tak, testuję funkcje prywatne, ponieważ chociaż są one testowane przez twoje publiczne metody, dobrze jest w TDD (Test Driven Design) przetestować najmniejszą część aplikacji. Ale funkcje prywatne nie są dostępne, gdy jesteś w klasie jednostki testowej. Oto, co robimy, aby przetestować nasze prywatne metody.

Dlaczego mamy prywatne metody?

Funkcje prywatne istnieją głównie w naszej klasie, ponieważ chcemy tworzyć czytelny kod w naszych metodach publicznych. Nie chcemy user of this class to call these methods directly, but through our public methods. Ponadto, nie chcemy zmieniać ich zachowania podczas rozszerzania klasy( w przypadku protected), stąd jest to prywatna.

Kiedy kodujemy, używamy test-driven-design (TDD). Oznacza to, że czasami natkniemy się na część funkcjonalności, która jest prywatna i chcemy przetestować. Funkcje prywatne nie są testowalne w phpUnit, ponieważ nie możemy uzyskać do nich dostępu w klasie testowej (są prywatne).

Myślimy tutaj są 3 rozwiązania:

1. Możesz przetestować swoje prywatne metody za pomocą publicznych metod

zalety

    Nie jest to konieczne, ponieważ nie jest to konieczne.]}

wady

    Programista musi zrozumieć metodę publiczną, podczas gdy chce tylko przetestować metodę prywatną.]}
  • nie testujesz najmniejszej testowalnej części aplikacji

2. Jeśli prywatność jest tak ważna, wtedy może jest to kod, aby utworzyć dla niego nową oddzielną klasę

zalety

  • Możesz refaktorować to do nowej klasy, ponieważ jeśli jest to ważne, inne klasy również mogą tego potrzebować
  • Jednostka testowalna jest obecnie metodą publiczną, więc testowalna

wady

  • nie chcesz tworzyć klasy, jeśli nie jest potrzebna i używana tylko przez klasa, z której pochodzi metoda
  • potencjał utrata wydajności z powodu dodanego napowietrzania

3. Zmień modyfikator dostępu na (końcowy) protected

zalety

  • testujesz najmniejszą testowalną część aplikacji. Kiedy używając final protected, funkcja nie będzie nadpisywalna (tylko jak prywatny)
  • brak utraty wydajności
  • No extra overhead

wady

  • zmieniasz prywatny dostęp do protected, co oznacza, że to dostępne dla dzieci
  • nadal potrzebujesz klasy Mock w klasie testowej, aby z niej korzystać

przykład

class Detective {
  public function investigate() {}
  private function sleepWithSuspect($suspect) {}
}
Altered version:
class Detective {
  public function investigate() {}
  final protected function sleepWithSuspect($suspect) {}
}
In Test class:
class Mock_Detective extends Detective {

  public test_sleepWithSuspect($suspect) 
  {
    //this is now accessible, but still not overridable!
    $this->sleepWithSuspect($suspect);
  }
}

Więc nasza jednostka testowa może teraz wywołać test_sleepWithSuspect, aby przetestować naszą poprzednią funkcję prywatną.

 48
Author: eddy147,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-25 07:58:55

Myś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ć skierowane twoje testy jednostkowe.

Gdy już masz jakieś solidne testy jednostkowe napisane dla obiektu, nie chcesz wracać i zmieniać tych testów tylko dlatego, że zmieniła się implementacja stojąca za interfejsem. W tej sytuacji zrujnowałeś spójność testów jednostkowych.

 22
Author: 17 of 26,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 19:59:57

Jeśli metoda prywatna jest dobrze zdefiniowana (tzn. ma funkcję, która jest testowalna i nie ma się zmieniać w czasie), to tak. Testuję wszystko, co można przetestować tam, gdzie ma to sens.

Na przykład Biblioteka szyfrująca może ukryć fakt, że wykonuje szyfrowanie blokowe metodą prywatną, która szyfruje tylko 8 bajtów na raz. Napisałbym do tego test jednostkowy - nie ma się zmieniać, mimo że jest ukryty, a jeśli się zepsuje (ze względu na przyszłe wyniki ulepszenia, na przykład) to chcę wiedzieć, że zepsuła się funkcja prywatna, a nie tylko jedna z funkcji publicznych.

Przyspiesza debugowanie później.

- Adam

 18
Author: Adam Davis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 20:11:39

Jeśli twoja prywatna metoda nie jest testowana przez wywołanie publicznych metod, to co ona robi? Mówię o prywatnym, nie chronionym ani przyjacielem.

 17
Author: chrissie1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 20:04:21

Jeśli tworzysz test driven (TDD), przetestujesz swoje prywatne metody.

 13
Author: Jader Dias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-16 17:08:44

Nie lubię testować prywatnych funkcji z kilku powodów. Są one następujące (są to główne punkty dla ludzi TLDR): {]}

  1. zazwyczaj, gdy kusisz się, aby przetestować prywatną metodę klasy, to zapach designu.
  2. można je przetestować za pośrednictwem publicznej interfejs (czyli jak chcesz je przetestować, bo tak klient zadzwoni/z nich skorzysta). Można uzyskać fałszywe poczucie bezpieczeństwa poprzez widząc Zielone światło na wszystkich zdających testów dla Twojego prywatne metody. Znacznie lepiej/bezpieczniej jest testować przypadki brzegowe na prywatnych funkcjach za pośrednictwem publicznego interfejsu.
  3. ryzykujesz poważne powielanie testów (testy, które wyglądają / czują bardzo podobne) poprzez testowanie prywatnych metod. To ma duże znaczenie konsekwencje, gdy zmieniają się wymagania, o wiele więcej testów niż trzeba będzie złamać. Może również umieścić cię w miejscu, w którym jest trudno refaktorować ze względu na zestaw testów...który jest ostatecznym ironia, ponieważ zestaw testów jest po to, aby pomóc ci bezpiecznie przeprojektowanie i refaktor!

Wyjaśnię każdy z nich na konkretnym przykładzie. Okazuje się, że 2) i 3) są ze sobą nieco zawile powiązane, więc ich przykład jest podobny, chociaż uważam je za osobne powody, dla których nie należy testować prywatnych metod.

Jest jeden raz, kiedy uważam testowanie prywatnych metod za właściwe, ale później omówię je bardziej szczegółowo.

Zastanawiam się również, dlaczego TDD nie jest poprawnym pretekstem do testowania prywatnych metod w bardzo koniec.

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ć/przeczytać jego książkę "Working Effectively with Legacy Code". Jest osobą, o której warto wiedzieć, jeśli jesteś profesjonalnym inżynierem oprogramowania / programistą). Istnieją inne (anty)wzorce, które powodują pojawianie się tego problemu, ale jest to zdecydowanie najczęstszy, na który się natknąłem. Klasy "Iceberg" mają jedną metodę publiczną, a pozostałe są prywatne (dlatego kuszące jest testowanie metod prywatnych). Nazywa się to klasą "lodową", ponieważ zwykle istnieje metoda samotna Publiczna, ale reszta funkcjonalności jest ukryta pod wodą w postaci metod prywatnych. Może to wyglądać mniej więcej tak:

Oceniacz Reguł

Na przykład, możesz chcieć przetestować GetNextToken(), wywołując go kolejno na łańcuchu znaków i widząc, że zwraca oczekiwany wynik. Taka funkcja gwarantuje test: to zachowanie nie jest trywialne, zwłaszcza jeśli Twoje reguły tokenizacji są złożone. Udawajmy, że to nie jest takie skomplikowane i chcemy po prostu linkować w żetonach ograniczonych przestrzenią. Więc piszesz test, może wygląda coś takiego (jakiś agnostyk językowy psuedo-code, mam nadzieję, że pomysł jest jasny): {]}

TEST_THAT(RuleEvaluator, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    re = RuleEvaluator(input_string);

    ASSERT re.GetNextToken() IS "1";
    ASSERT re.GetNextToken() IS "2";
    ASSERT re.GetNextToken() IS "test";
    ASSERT re.GetNextToken() IS "bar";
    ASSERT re.HasMoreTokens() IS FALSE;
}
To wygląda całkiem nieźle. Chcemy mieć pewność, że zachowujemy to zachowanie jako wprowadzamy zmiany. Ale GetNextToken() jest} prywatną funkcją! Więc nie możemy go tak przetestować, ponieważ nie będzie nawet kompilować (zakładając, że używamy jakiegoś języka, który faktycznie wymusza publiczny/prywatny, w przeciwieństwie do niektórych języków skryptowych, takich jak Python). Ale co z zmianą klasy RuleEvaluator, aby podążała za zasadą jednej odpowiedzialności (zasada jednej odpowiedzialności)? Na przykład, wydaje się, że parser, tokenizer i evaluator są zablokowane w jednej klasie. Czy nie byłoby lepiej po prostu rozdzielić te obowiązki? Poza tym, jeśli utworzysz klasę Tokenizer, to metodami publicznymi będą HasMoreTokens() i GetNextTokens(). Klasa RuleEvaluator może mieć obiekt Tokenizer jako członek. Teraz możemy zachować ten sam test jak powyżej, z tym wyjątkiem, że testujemy klasę Tokenizer zamiast klasy RuleEvaluator.

Oto Jak to może wyglądać w UML:

Reguła Ewaluator Refakturowany

Zauważ, że ten nowy projekt zwiększa modułowość, więc potencjalnie możesz ponownie użyć tych klas w innych częściach Twojego systemu (zanim nie mogłeś, metody prywatne z definicji nie nadają się do wielokrotnego użytku). Jest to główna zaleta złamania zasady, wraz ze zwiększoną zrozumiałością/lokalnością.

Test wyglądałby bardzo podobnie, z tym wyjątkiem, że w rzeczywistości skompilowałby się tym razem, ponieważ metoda GetNextToken() jest teraz Publiczna w klasie Tokenizer:

TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);

    ASSERT tokenizer.GetNextToken() IS "1";
    ASSERT tokenizer.GetNextToken() IS "2";
    ASSERT tokenizer.GetNextToken() IS "test";
    ASSERT tokenizer.GetNextToken() IS "bar";
    ASSERT tokenizer.HasMoreTokens() IS FALSE;
}

Testowanie prywatnych komponentów przez publiczny interfejs i unikanie powielania testów

Even if you don ' t think możesz podzielić swój problem na mniej modułowych komponentów (co można 95% czasu, jeśli po prostu spróbować , aby to zrobić), możesz po prostu przetestować funkcje prywatne za pośrednictwem publicznego interfejsu. Wiele razy członkowie prywatni nie są warte testowania, ponieważ będą testowane przez publiczny interfejs. Wiele razy to, co widzę, to testy, które wyglądają Bardzo podobnie, ale testują dwie różne funkcje/metody. Kończy się to tym, że gdy wymagania się zmieniają (i zawsze tak), teraz masz 2 zepsute testy zamiast 1. A jeśli naprawdę przetestowałeś wszystkie swoje prywatne metody, możesz mieć więcej niż 10 zepsutych testów zamiast 1. W skrócie, testowanie funkcji prywatnych (przez użycie FRIEND_TEST lub upublicznienie ich lub użycie reflection), które mogłyby być testowane przez publiczny interfejs, może spowodować powielanie testów. Naprawdę tego nie chcesz, bo nic nie boli bardziej niż twój zestaw testów, który cię spowalnia. Ma skracać czas rozwoju i zmniejszać koszty utrzymania! Jeśli przetestujesz prywatne metody, które są testowane przez publiczny interfejs, zestaw testów może bardzo dobrze zrobić odwrotnie i aktywnie zwiększyć koszty konserwacji i wydłużyć czas rozwoju. Kiedy upublicznisz funkcję prywatną lub użyjesz czegoś takiego jak FRIEND_TEST i / lub reflection, zazwyczaj będziesz tego żałować na dłuższą metę.

Rozważ następującą możliwą implementację klasy Tokenizer:

Tutaj wpisz opis obrazka

Let ' s powiedzmy, że {[19] } jest odpowiedzialny za zwracanie tablicy tak, że każdy element w tablicy jest tokenem. Ponadto powiedzmy, że GetNextToken() jest po prostu iteratorem nad tym wektorem. Więc Twój publiczny test może wyglądać tak:

TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);

    ASSERT tokenizer.GetNextToken() IS "1";
    ASSERT tokenizer.GetNextToken() IS "2";
    ASSERT tokenizer.GetNextToken() IS "test";
    ASSERT tokenizer.GetNextToken() IS "bar";
    ASSERT tokenizer.HasMoreTokens() IS false;
}

Udawajmy, że mamy to, co Michael Feather nazywa narzędziem do obmacywania. Jest to narzędzie, które pozwala dotykać prywatnych części innych ludzi. Przykładem jest FRIEND_TEST z googletest, lub reflection, jeśli język go obsługuje.

TEST_THAT(TokenizerTest, canGenerateSpaceDelimtedTokens)
{
    input_string = "1 2 test bar"
    tokenizer = Tokenizer(input_string);
    result_array = tokenizer.SplitUpByDelimiter(" ");

    ASSERT result.size() IS 4;
    ASSERT result[0] IS "1";
    ASSERT result[1] IS "2";
    ASSERT result[2] IS "test";
    ASSERT result[3] IS "bar";
}

Cóż, teraz Załóżmy, że wymagania się zmieniają, a tokenizacja staje się znacznie bardziej złożona. Decydujesz, że prosty ogranicznik łańcucha znaków nie wystarczy i potrzebujesz klasy Delimiter do obsługi zadania. Oczywiście spodziewasz się złamania jednego testu, ale ból wzrasta, gdy testujesz prywatne funkcje.

Kiedy testowanie prywatnych metod może być właściwe?

W oprogramowaniu nie ma "jednego rozmiaru dla wszystkich". Czasami jest dobrze (a właściwie idealnie) "łamać zasady". Zdecydowanie popieram nie testuj prywatnej funkcjonalności, kiedy możesz. Są dwie główne sytuacje, kiedy myślę, że jest w porządku:

  1. Pracowałem intensywnie ze starszymi systemami (dlatego jestem tak 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 charakterystyki" do linii bazowej.

  2. Jesteś w pośpiechu, i musisz zrobić najszybciej jak to możliwe Dla tutaj i teraz. Na dłuższą metę nie chcesz testować prywatnych metod. Ale powiem, że zazwyczaj refaktorowanie zajmuje trochę czasu, aby rozwiązać problemy projektowe. I czasami trzeba wysłać w ciągu tygodnia. W porządku: zrób szybkie i brudne i przetestuj prywatne metody za pomocą narzędzia do obmacywania, jeśli uważasz, że jest to najszybszy i najbardziej niezawodny sposób na wykonanie zadania. Ale zrozum, że to, co zrobiłeś, było nieoptymalne na dłuższą metę, i proszę rozważyć powrót do niego (lub, jeśli został zapomniany o ale zobaczysz to później, napraw to).

Są prawdopodobnie inne sytuacje, w których jest to w porządku. Jeśli uważasz, że to w porządku i masz dobre uzasadnienie, to zrób to. Nikt cię nie powstrzyma. Po prostu należy pamiętać o potencjalnych kosztach.

Wymówka TDD

Na marginesie, naprawdę nie lubię ludzi, którzy używają TDD jako pretekstu do testowania prywatnych metod. praktykuję TDD i nie sądzę, że TDD zmusza cię do tego. Możesz napisać swój test (dla public interface), a następnie napisać kod, aby ten interfejs spełniał Czasami piszę test dla publicznego interfejsu i spełnię go, pisząc jedną lub dwie mniejsze prywatne metody, jak również (ale nie testuję prywatnych metod bezpośrednio, ale wiem, że one działają lub mój publiczny test byłby zawodzący). Jeśli będę musiał przetestować przypadki brzegowe tej prywatnej metody, napiszę całą masę testów, które trafią do nich przez mój publiczny interfejs. jeśli nie możesz wymyślić, jak uderzyć w przypadki edge, to jest silnym znakiem, że musisz refaktorować na małe komponenty, każdy z własnymi metodami publicznymi. To znak, że Twoje prywatne funkcje robią za dużo i poza zasięgiem klasy .

Czasami zdarza mi się napisać test, który jest zbyt duży, aby przeżuć w tej chwili, więc myślę: "EH, wrócę do tego testu później, gdy będę miał więcej API do pracy" (skomentuję to i zachowam to w głębi mojego umysłu). To jest miejsce, gdzie wielu deweloperów, których spotkałem będzie wtedy zacznij pisać testy dla ich prywatnej funkcjonalności, używając TDD jako kozła ofiarnego. Mówią: "Och, cóż, potrzebuję innego testu, ale aby napisać ten test, potrzebuję tych prywatnych metod. Dlatego, ponieważ nie mogę napisać żadnego kodu produkcyjnego bez napisania testu, muszę napisać test dla prywatnej metody."Ale to, co naprawdę muszą robić, to refaktoryzować na mniejsze i wielokrotnego użytku komponenty zamiast dodawać / testować kilka prywatnych metod do ich obecnego klasy.

Uwaga:

Odpowiedziałem na podobne pytanie o testowanie prywatnych metod za pomocą GoogleTest jakiś czas temu. W większości zmodyfikowałem tę odpowiedź, aby była bardziej agnostyczna językowo.

P. S. oto odpowiedni wykład o zajęciach i narzędziach do obmacywania autorstwa Michaela Feathersa: https://www.youtube.com/watch?v=4cVZvoFGJTU

 12
Author: Matt Messersmith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-20 21:09:10

Nie jestem ekspertem w tej dziedzinie, ale testy jednostkowe powinny testować zachowanie, a nie implementację. Prywatne metody są ściśle częścią implementacji, więc IMHO nie należy testować.

 11
Author: maxbog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 20:00:05

Testujemy prywatne metody przez wnioskowanie, przez co mam na myśli, że szukamy całkowitego pokrycia testu klasowego na poziomie co najmniej 95%, ale nasze testy mają tylko wywoływać publiczne lub wewnętrzne metody. Aby uzyskać zasięg, musimy wykonać wiele połączeń publicznych / wewnętrznych w oparciu o różne scenariusze, które mogą wystąpić. To sprawia, że nasze testy są bardziej skoncentrowane na celu kodu, który testują.

Odpowiedź Trumpi na post, który podlinkowałeś jest najlepsza.

 11
Author: Tom Carr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 20:02:05

Testy jednostkowe moim zdaniem służą do testowania metod publicznych. Twoje publiczne metody używają Twoich prywatnych metod, więc pośrednio są one również testowane.

 8
Author: scubabbl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 19:58:55

Od jakiegoś czasu duszę się nad tym problemem, zwłaszcza 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.

  1. testowanie prywatnych metod, TDD i refaktoryzacji testowej
  2. Test-Driven Development to nie Testowanie

W Skrócie:

  • Stosując techniki test driven development (design), metody prywatne powinny powstają tylko podczas procesu re-faktoringu już działającego i przetestowanego kodu.

  • Ze względu na samą naturę procesu, każdy bit prostej funkcjonalności implementacji wydobyty z dokładnie przetestowanej funkcji będzie testowany samodzielnie (tj. pośredni zakres testowania).

Wydaje mi się wystarczająco jasne, że w początkowej części kodowania większość metod będzie funkcjami wyższego poziomu, ponieważ są one enkapsulujące / opisujące projekt.

Dlatego te metody będą publiczne, a ich testowanie będzie wystarczająco łatwe.

Prywatne metody pojawią się później, gdy wszystko będzie dobrze działać i będziemy ponownie faktorować ze względu na czytelność i czystość .

 7
Author: dkinzer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-17 14:45:13

Jak zacytowano powyżej, " jeśli nie przetestujesz swoich prywatnych metod, skąd wiesz, że nie pękną?"

Jest to poważny problem. Jednym z ważniejszych punktów testów jednostkowych jest wiedzieć, gdzie, kiedy i jak coś się zepsuło. W ten sposób zmniejszając znaczną ilość wysiłku w zakresie rozwoju i kontroli jakości. Jeśli wszystko, co jest testowane, to społeczeństwo, to nie masz uczciwego pokrycia i określenia wewnętrznych klas.

Znalazłem jeden z najlepszych sposobów, aby to zrobić jest po prostu dodać referencję test do projektu i umieścić testy w klasie równoległej do metod prywatnych. Umieść odpowiednią logikę budowania, aby testy nie wbudowały się w ostateczny projekt.

Wtedy masz wszystkie zalety testowania tych metod i możesz znaleźć problemy w sekundach lub minutach lub godzinach.

Podsumowując, tak, przetestuj swoje prywatne metody.

 5
Author: Adron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-20 19:14:19

Jeśli nie przetestujesz swoich prywatnych metod, skąd wiesz, że się nie zepsują?

 4
Author: Billy Jo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 19:58:58

Nie powinieneś . Jeśli twoje prywatne metody mają wystarczająco dużo złożoności, które muszą być przetestowane, powinieneś umieścić je na innej klasie. Zachowaj wysoką spójność , klasa powinna mieć tylko jeden cel. Klasa public interface powinna wystarczyć.

 4
Author: fernandezdavid7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-21 15:11:19

To oczywiście zależne od języka. W przeszłości z c++ deklarowałem klasę testową jako klasę przyjacielską. Niestety, wymaga to, aby Twój kod produkcyjny wiedział o klasie testowej.

 2
Author: dvorak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 20:01:14

Rozumiem punkt widzenia, w którym prywatne metody są traktowane jako szczegóły implementacji i nie muszą być testowane. I trzymałbym się tej zasady, gdybyśmy mieli rozwijać się tylko poza obiektem. Ale czy my jesteśmy jakimś ograniczonym programistą, który rozwija się tylko poza obiektami, wywołując tylko swoje publiczne metody? Czy też rzeczywiście rozwijamy ten obiekt? Ponieważ nie jesteśmy związani z programowaniem poza obiektami, prawdopodobnie będziemy musieli wywołać te prywatne metody rozwijamy się w nowe publiczne. Czy nie byłoby wspaniale wiedzieć, że prywatna metoda opiera się wbrew wszelkim przeciwnościom?

Wiem, że niektórzy ludzie mogliby odpowiedzieć, że jeśli rozwijamy inną publiczną metodę do tego obiektu, to ta powinna być przetestowana i to wszystko(prywatna metoda mogłaby żyć bez testu). Ale dotyczy to również wszystkich publicznych metod obiektu: podczas tworzenia aplikacji webowej wszystkie publiczne metody obiektu są wywoływane z metod kontrolerów i stąd mogą być traktowane jako szczegóły implementacji dla kontrolerów.

Dlaczego więc testujemy obiekty jednostkowe? Ponieważ jest to naprawdę trudne, nie powiedzieć niemożliwe, aby mieć pewność, że testujemy metody kontrolerów z odpowiednim wejściem, które uruchomi wszystkie gałęzie kodu bazowego. Innymi słowy, im wyżej jesteśmy w stosie, tym trudniej jest przetestować wszystkie zachowania. Podobnie jest w przypadku metod prywatnych.

Dla mnie granica między prywatnymi i metody publiczne są kryterium psychologicznym, jeśli chodzi o testy. Kryteria, które liczą się dla mnie bardziej to:

  • czy metoda jest wywoływana więcej niż raz z różnych miejsc?
  • czy metoda jest wystarczająco zaawansowana, aby wymagać testów?
 2
Author: Olivier Pichon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-06 23:22:19

Jeśli testujemy poprawność logiki, a prywatna metoda niesie logikę, powinniśmy ją przetestować. Prawda? Więc dlaczego to pominiemy?

Pisanie testów opartych na widoczności metod jest całkowicie nieistotnym pomysłem.

 2
Author: Supun Wijerathne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-11 07:00:32

Jeśli okaże się, ż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 tam upubliczniam (obiekt Method). Następnie mogę łatwo przetestować wcześniej prywatną, ale teraz publiczną metodę, która teraz żyje na własnej klasie.

 1
Author: Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 16:14:15

Jeśli metoda jest wystarczająco znacząca/wystarczająco złożona, Zwykle zrobię ją "chronioną"i przetestuję. Niektóre metody pozostaną prywatne i przetestowane w sposób niejawny jako część testów jednostkowych dla metod publicznych/chronionych.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-24 08:39:57

Absolutnie tak. Na tym polega Testowanie jednostek. Metoda prywatna to jednostka. Bez testowania prywatnych metod TDD (Test Driven Development) byłoby niemożliwe,

 0
Author: Shpokas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-25 10:58:59

Widzę, że wiele osób myśli w tym samym kierunku: test na poziomie publicznym. ale czy nie tym zajmuje się nasz zespół QA? Testują wejście i oczekiwane wyjście. Jeśli jako programiści testujemy tylko publiczne metody, to po prostu wykonujemy zadanie QA i nie dodajemy żadnej wartości przez "testowanie jednostkowe".

 0
Author: aemorales1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-22 15:01:02

Odpowiedź na "Czy powinienem testować prywatne metody?"jest".......czasami". Zazwyczaj powinieneś testować pod kątem interfejsu swoich klas.

  • jednym z powodów jest to, że nie potrzebujesz podwójnego pokrycia dla funkcji.
  • innym powodem jest to, że jeśli zmienisz metody prywatne, będziesz musiał aktualizować każdy test dla nich, nawet jeśli interfejs Twojego obiektu w ogóle się nie zmienił.

Oto przykład:

class Thing
  def some_string
    one + two
  end

  private 

  def one
    'aaaa'
  end

  def two
    'bbbb'
  end

end


class RefactoredThing
def some_string
    one + one_a + two + two_b
  end

  private 

  def one
    'aa'
  end

  def one_a
    'aa'
  end

  def two
    'bb'
  end

  def two_b
    'bb'
  end
end

W RefactoredThing masz teraz 5 testów, 2 z których trzeba było zaktualizować do refaktoryzacji, ale funkcjonalność obiektu naprawdę się nie zmieniła. Powiedzmy więc, że rzeczy są bardziej złożone i masz jakąś metodę, która definiuje kolejność wyjścia, taką jak:

def some_string_positioner
  if some case
  elsif other case
  elsif other case
  elsif other case
  else one more case
  end
end

To nie powinno być uruchamiane przez zewnętrznego użytkownika, ale twoja klasa hermetyzacji może być zbyt ciężka, aby uruchamiać tyle logiki przez nią w kółko. W tym przypadku może wolisz wyodrębnić to do osobnej klasy, dać tej klasie interfejs i test przeciw.

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 wyjście jest poprawne. Myślisz: "muszę przetestować tę prywatną metodę!". Czy może możesz uczynić swój obiekt lżejszym, przekazując niektóre ciężkie prace jako parametr inicjalizacji? Wtedy możesz podać coś lżejszego i przetestować to.

 0
Author: unflores,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-14 15:52:14

Nie powinieneś testować prywatnych metod Dlaczego? a ponadto popularny framework do szydzenia, taki jak Mockito, nie zapewnia wsparcia dla testowania prywatnych metod.

 0
Author: cammando,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:59