W programowaniu TDD pierwszą rzeczą, którą zwykle robisz, jest utworzenie interfejsu, a następnie rozpoczęcie pisania testów jednostkowych w odniesieniu do tego interfejsu. W miarę postępów w procesie TDD skończyłoby się na utworzeniu klasy, która implementuje interfejs, a następnie w pewnym momencie test jednostkowy przeszedłby.
Teraz moje pytanie dotyczy prywatnych i chronionych metod, które być może będę musiał napisać w mojej klasie w celu wsparcia metod / właściwości udostępnianych przez interfejs:
Czy metody prywatne w klasie powinny mieć własne testy jednostkowe?
Czy chronione metody w klasie powinny mieć własne testy jednostkowe?
Moje myśli:
Zwłaszcza, że koduję do interfejsów, nie powinienem martwić się o metody chronione / prywatne, ponieważ są to czarne skrzynki.
Ponieważ używam interfejsów, piszę testy jednostkowe, aby sprawdzić, czy zdefiniowany kontrakt jest prawidłowo zaimplementowany przez różne klasy implementujące interfejs, więc ponownie nie powinienem martwić się o metody prywatne / chronione i powinny być wykonywane za pomocą testów jednostkowych, które wywołują metody / właściwości zdefiniowane przez interfejs.
Jeśli pokrycie mojego kodu nie pokazuje, że metody chronione / prywatne są trafione, oznacza to, że nie mam odpowiednich testów jednostkowych lub mam kod, który nie jest używany i powinien zostać usunięty.
źródło
Odpowiedzi:
Nie, nie myślę o testowaniu metod prywatnych lub chronionych. Prywatne i chronione metody klasy nie są częścią interfejsu publicznego, więc nie ujawniają publicznego zachowania. Generalnie te metody są tworzone przez refaktoryzacje, które stosujesz po tym, jak Twój test zmieni kolor na zielony.
Więc te prywatne metody są testowane niejawnie przez testy, które potwierdzają zachowanie twojego interfejsu publicznego.
Mówiąc bardziej filozoficznie, pamiętaj, że testujesz zachowanie, a nie metody. Więc jeśli pomyślisz o zestawie rzeczy, które może zrobić testowana klasa, o ile możesz przetestować i potwierdzić, że klasa zachowuje się zgodnie z oczekiwaniami, czy istnieją prywatne (i chronione) metody, które są używane wewnętrznie przez klasę do implementacji to zachowanie jest nieistotne. Te metody są szczegółami implementacji zachowania publicznego.
źródło
Nie zgadzam się z większością plakatów.
Najważniejsza zasada to: KOD ROBOCZY PRZERWA TEORETYCZNE ZASADY dotyczące publicznego / chronionego / prywatnego.
Twój kod powinien zostać dokładnie przetestowany. Jeśli możesz się tam dostać, pisząc testy dla metod publicznych, które wystarczająco ćwiczą metody chronione / prywatne, to świetnie.
Jeśli nie możesz, albo refaktoryzuj, abyś mógł, albo nagnij chronione / prywatne reguły.
Jest świetna historia o psychologu, który dał dzieciom test. Dał każdemu dziecku dwie drewniane deski z liną przymocowaną na każdym końcu i poprosił je, aby przeszły przez pokój bez dotykania podłogi tak szybko, jak to możliwe. Wszystkie dzieci używały desek jak małych nart, po jednej nodze na każdej desce, trzymając je za liny i ślizgając się po podłodze. Następnie dał im to samo zadanie, ale używając tylko JEDNEJ planszy. Obracali się / „szli” po podłodze, po jednej nodze na każdym końcu pojedynczej deski - i byli SZYBSZY!
To, że Java (lub jakikolwiek inny język) ma jakąś funkcję (prywatną / chronioną / publiczną), niekoniecznie oznacza, że piszesz lepszy kod, ponieważ go używasz!
Teraz zawsze będzie można zoptymalizować / zminimalizować ten konflikt. W większości języków możesz uczynić metodę chronioną (zamiast publiczną) i umieścić klasę testową w tym samym pakiecie (lub czymkolwiek), a metoda będzie dostępna do testowania. Istnieją adnotacje, które mogą pomóc, opisane na innych plakatach. Możesz użyć refleksji, aby dostać się do prywatnych metod (fuj).
Liczy się również kontekst. Jeśli piszesz API do użytku przez osoby z zewnątrz, ważniejsze jest publiczne / prywatne. Jeśli to projekt wewnętrzny - kogo to naprawdę obchodzi?
Ale pod koniec dnia zastanów się, ile błędów spowodował brak testów. Następnie porównaj z liczbą błędów spowodowanych metodami „nadmiernie widocznymi”. Ta odpowiedź powinna wpłynąć na twoją decyzję.
źródło
Napisałeś:
Pozwól, że przeformułuję to w języku BDD :
Dlatego nie testujesz metod prywatnych - ponieważ test jest przykładem tego, jak używać tej klasy i nie możesz ich właściwie używać. Coś, co możesz zrobić, jeśli chcesz, to delegowanie obowiązków w metodach prywatnych do klasy współpracującej, a następnie mock / stub tego pomocnika.
W przypadku metod chronionych mówisz, że klasa, która rozszerza twoją klasę, powinna mieć określone zachowanie i zapewniać pewną wartość. Następnie możesz użyć rozszerzeń swojej klasy, aby zademonstrować to zachowanie. Na przykład, jeśli piszesz uporządkowaną klasę kolekcji, możesz chcieć zademonstrować, że dwa rozszerzenia o tej samej zawartości wykazały równość.
Mam nadzieję że to pomoże!
źródło
Kiedy piszesz testy jednostkowe dla swojej klasy, nie musisz koniecznie dbać o to, czy funkcjonalność klasy jest implementowana bezpośrednio w metodzie w interfejsie publicznym, czy też jest zaimplementowana w szeregu metod prywatnych. Więc tak, powinieneś testować swoje metody prywatne, ale nie powinieneś w tym celu wywoływać ich bezpośrednio z kodu testowego (bezpośrednie testowanie metod prywatnych ściśle łączy Twoją implementację z testami i sprawia, że refaktoryzacja jest niepotrzebnie trudna).
Metody chronione tworzą inny kontrakt między twoją klasą a jej przyszłymi elementami podrzędnymi, więc naprawdę powinieneś testować je w podobnym stopniu jak interfejs publiczny, aby upewnić się, że kontrakt jest dobrze zdefiniowany i wykonywany.
źródło
Nie! Tylko interfejsy testowe.
Jedną z dużych zalet TDD jest zapewnienie, że interfejs działa bez względu na to, w jaki sposób zaimplementowałeś metody prywatne.
źródło
Kończąc to, co powiedzieli inni powyżej, powiedziałbym, że metody chronione są częścią pewnego rodzaju interfejsu: po prostu tak się składa, że jest to narażone na dziedziczenie, a nie na kompozycję, o czym każdy myśli, rozważając interfejsy.
Oznaczanie metody jako chronionej zamiast prywatnej oznacza, że oczekuje się, że będzie ona używana przez kod strony trzeciej, więc należy zdefiniować i przetestować jakiś rodzaj umowy, jak to ma miejsce w przypadku normalnych interfejsów zdefiniowanych przez metody publiczne, które są otwarte zarówno na dziedziczenie, jak i na kompozycję .
źródło
Istnieją dwa powody, dla których warto pisać testy:
Podejście (1) Zapewnienie oczekiwanego zachowania:
Podczas potwierdzania oczekiwanego zachowania chcesz się upewnić, że kod działa tak, jak myślisz, że powinien. Jest to w rzeczywistości zautomatyzowany sposób wykonywania rutynowej ręcznej weryfikacji, którą każdy programista wykonałby podczas implementacji dowolnego rodzaju kodu:
To są pytania, na które wszyscy odpowiadamy w naszych głowach i zwykle próbujemy wykonać kod również w naszych głowach, upewniając się, że wygląda na to, że działa. W takich przypadkach często warto poprosić komputer o udzielenie ostatecznej odpowiedzi. Więc piszemy test jednostkowy, który zapewnia, że tak. Daje nam to zaufanie do naszego kodu, pomaga nam wcześnie znajdować usterki, a nawet może pomóc w faktycznym wdrożeniu kodu.
Warto to zrobić wszędzie tam, gdzie uważasz, że jest to konieczne. Każdy kod, który jest trochę trudny do zrozumienia lub nietrywialny. Nawet trywialny kod mógłby na tym skorzystać. Chodzi o twoją własną pewność siebie. To, jak często to robisz i jak daleko zajdziesz, zależy od twojej własnej satysfakcji. Przestań, kiedy możesz śmiało odpowiedzieć Tak na: Czy na pewno to działa?
W przypadku tego rodzaju testów nie obchodzi Cię widoczność, interfejsy itp., Zależy Ci tylko na tym, aby kod działał. Więc tak, przetestowałbyś prywatne i chronione metody, gdybyś uważał, że trzeba je przetestować, aby odpowiedzieć Tak na pytanie.
Podejście (2) Zapobieganie regresji zachowania:
Kiedy już masz działający kod, musisz mieć mechanizm, który chroni go przed przyszłymi uszkodzeniami. Gdyby nikt nigdy więcej nie dotykał twojego źródła i konfiguracji, nie potrzebujesz tego, ale w większości przypadków ty lub inni będziecie dotykać źródła i konfiguracji twojego oprogramowania. To wewnętrzne majsterkowanie jest wysoce prawdopodobne, że złamie twój działający kod.
Mechanizmy istnieją już w większości języków jako sposób ochrony przed tymi uszkodzeniami. Funkcje widoczności to jeden mechanizm. Prywatna metoda jest izolowana i ukryta. Hermetyzacja to kolejny mechanizm, w którym dokonuje się podziału rzeczy, tak aby zmiana innych przedziałów nie wpływała na innych.
Ogólny mechanizm tego nazywa się: kodowanie do granicy. Tworząc granice między częściami kodu, chronisz wszystko wewnątrz granicy przed rzeczami znajdującymi się poza nią. Granice stają się punktem interakcji i umową, poprzez którą rzeczy oddziałują.
Oznacza to, że zmiany granicy, albo przez złamanie jej interfejsu, albo przez złamanie jej oczekiwanego zachowania, mogą uszkodzić i prawdopodobnie złamać inne granice, na których polegały. Dlatego dobrym pomysłem jest przeprowadzenie testu jednostkowego, który jest ukierunkowany na te granice i zapewnia, że nie zmieniają się one pod względem semantycznym i zachowania.
To jest twój typowy test jednostkowy, o którym większość mówi o TDD lub BDD. Chodzi o to, aby granice utwardzały się i chroniły przed zmianami. Nie chcesz testować w tym celu metod prywatnych, ponieważ metoda prywatna nie jest granicą. Metody chronione są ograniczoną granicą i chroniłbym je. Nie są wystawieni na działanie świata, ale nadal są wystawieni na działanie innych przedziałów lub „Jednostek”.
Co z tym zrobić?
Jak widzieliśmy, istnieje dobry powód do testowania jednostkowego metod publicznych i chronionych, aby zapewnić, że nasze interfejsy się nie zmieniają. Jest też dobry powód, aby przetestować metody prywatne, aby potwierdzić, że nasza implementacja działa. Więc czy powinniśmy przetestować je wszystkie?
Tak i nie.
po pierwsze : Przetestuj wszystkie metody, które Twoim zdaniem wymagają ostatecznego dowodu, że działa w większości przypadków, aby mieć pewność, że kod działa, niezależnie od widoczności. Następnie wyłącz te testy. Zrobili tam pracę.
W końcu : pisz testy dla swoich granic. Miej test jednostkowy dla każdego punktu, który będzie używany przez inne jednostki twojego systemu. Upewnij się, że ten test potwierdza kontrakt semantyczny, nazwę metody, liczbę argumentów itp. A także upewnij się, że test potwierdza dostępne zachowanie jednostki. Twój test powinien zademonstrować, jak korzystać z urządzenia i co może zrobić. Pozostaw te testy włączone, aby były uruchamiane przy każdym wypychaniu kodu.
UWAGA: Przyczyną wyłączenia pierwszego zestawu testów jest umożliwienie wykonania prac refaktoryzacji. Test aktywny to sprzężenie kodu. Zapobiega przyszłej modyfikacji testowanego kodu. Chcesz tego tylko dla swoich interfejsów i umów interakcji.
źródło
Nie, nie powinieneś testować prywatnych metod (jak byś nie używał czegoś okropnego jak refleksja). W przypadku metod chronionych jest nieco mniej oczywiste w C #, że można sprawić, by elementy chronione były wewnętrzne i myślę, że można to zrobić, aby przetestować klasy pochodne, które implementują całą swoją funkcjonalność za pomocą metod wzorca szablonu.
Ale ogólnie, jeśli myślisz, że twoje metody publiczne robią za dużo, to czas na refaktoryzację twoich klas na bardziej atomowe klasy, a następnie przetestowanie tych klas.
źródło
Ja również zgadzam się z odpowiedzią @ kwbeam dotyczącą nie testowania metod prywatnych. Jednak ważna kwestia, którą chciałbym podkreślić - metody chronione SĄ częścią eksportowanego interfejsu API klasy i dlatego MUSZĄ zostać przetestowane.
Metody chronione mogą nie być publicznie dostępne, ale z pewnością zapewniasz sposób, aby podklasy ich używały / zastępowały. Coś spoza klasy może uzyskać do nich dostęp, dlatego musisz upewnić się, że ci chronieni członkowie zachowują się w oczekiwany sposób. Więc nie testuj metod prywatnych, ale testuj metody publiczne i chronione.
Jeśli uważasz, że masz prywatną metodę, która zawiera logikę krytyczną, spróbuję wyodrębnić ją do oddzielnego obiektu, wyodrębnić i zapewnić sposób przetestowania jego zachowania.
Mam nadzieję, że to pomoże!
źródło
Jeśli zależy Ci na wysokim pokryciu kodu (sugeruję, że powinieneś), powinieneś przetestować wszystkie metody, niezależnie od tego, czy są prywatne czy chronione.
Protected to rodzaj innego punktu do dyskusji, ale podsumowując, w ogóle nie powinno go tam być. Albo przerywa hermetyzację we wdrożonym kodzie, albo zmusza cię do dziedziczenia z tej klasy, aby ją przetestować, nawet czasami nie musisz dziedziczyć.
Samo ukrycie metody klientowi (uczynienie go prywatną) nie daje mu uprawnienia do tego, aby nie podlegać audytowi. Dlatego można je testować metodami publicznymi, jak wspomniano wcześniej.
źródło
Zgadzam się ze wszystkimi: odpowiedź na twoje pytanie brzmi „nie”.
Rzeczywiście, masz całkowitą rację ze swoim podejściem i przemyśleniami, zwłaszcza dotyczącymi pokrycia kodu.
Dodam też, że pytanie (i odpowiedź „nie”) dotyczy również metod publicznych, które możesz wprowadzić na zajęcia.
Również dla C ++ (i powinienem myśleć tylko o C ++) implementuję interfejsy używając tylko prywatnych metod, aby wskazać, że klasa powinna być używana tylko przez interfejs, który implementuje. Uniemożliwia mi to błędne wywoływanie nowych metod dodanych do mojej implementacji z moich testów
źródło
Dobry projekt oznacza podzielenie aplikacji na wiele testowalnych jednostek. Po wykonaniu tej czynności niektóre jednostki są narażone na publiczny interfejs API, ale inne mogą nie być. Ponadto punkty interakcji między eksponowanymi jednostkami a tymi „wewnętrznymi” jednostkami również nie są częścią publicznego API.
Myślę, że gdy już będziemy mieli identyfikowalną jednostkę, testy jednostkowe przyniosą korzyści, niezależnie od tego, czy zostaną ujawnione za pośrednictwem publicznego interfejsu API, czy nie.
źródło