Czy rozsądne jest nie pisanie testów jednostkowych, ponieważ mają one tendencję do komentowania w późniejszym terminie lub ponieważ testy integracyjne są bardziej wartościowe?


35

Rozmawiałem o testach jednostkowych / integracji z kolegą, a on przedstawił interesujący argument przeciwko pisaniu testów jednostkowych. Jestem wielkim zwolennikiem testów jednostkowych (przede wszystkim JUnit), ale jestem zainteresowany, aby usłyszeć opinie innych, ponieważ przedstawił kilka interesujących uwag.

Podsumowując swoje punkty:

  • Gdy wystąpią poważne zmiany w kodzie (nowy zestaw POJO, refaktoryzacja dużych aplikacji itp.), Testy jednostkowe są raczej komentowane niż przerabiane.
  • Lepiej poświęcić czas na testy integracyjne obejmujące przypadki użycia, dzięki którym testy o mniejszym zasięgu są mniej / wcale nie ważne.

Myśli na ten temat? Nadal jestem testem jednostkowym (ponieważ konsekwentnie widzę, że produkuje ulepszony kod), chociaż testy integracyjne brzmią co najmniej tak samo cennie.


9
Sam to powiedziałeś: pisanie testów jednostkowych daje lepszy kod, ponieważ zmusza cię do napisania kodu, który można przetestować. Kod testowany przez jednostkę ma wiele bardzo ważnych właściwości, które poprawiają jego ogólną jakość.
Robert Harvey,

1
@Robert Harvey - zgodził się - chciałbym zobaczyć listę tych nieruchomości.
Jeff Levine,

18
Jeśli chodzi o pierwszy punkt - zasadniczo mówisz, że wadą testów jednostkowych jest to, że nie działają one, gdy ich nie używasz. Możesz powiedzieć to samo o każdej innej praktyce. Również użycie pasywnego głosu rzuca uwagę na fakt, że ktoś aktywnie komentuje testy jednostkowe. Wygląda więc na to, że nie masz wpisowego od programistów w zespole, co stanowi inny problem.
JacquesB,


Odpowiedzi:


62

Zwykle opowiadam się po stronie twojego przyjaciela, ponieważ zbyt często testy jednostkowe testują złe rzeczy .

Testy jednostkowe nie są z natury złe. Ale często testują szczegóły implementacji, a nie przepływ wejściowy / wyjściowy. Kiedy tak się dzieje, kończysz się całkowicie bezcelowymi testami. Moją własną zasadą jest, że dobry test jednostkowy mówi ci, że właśnie coś złamałeś; zły test jednostkowy mówi tylko, że właśnie coś zmieniłeś.

Przykładem z góry mojej głowy jest test, który został wpięty w WordPress kilka lat temu. Testowana funkcjonalność obracała się wokół filtrów, które się nawzajem wywoływały, a testy weryfikowały, czy wywołania zwrotne będą wtedy wywoływane we właściwej kolejności. Ale zamiast (a) uruchomienia łańcucha w celu sprawdzenia, czy wywołania zwrotne są wywoływane w oczekiwanej kolejności, testy koncentrowały się na (b) odczytaniu stanu wewnętrznego, który prawdopodobnie nie powinien był zostać ujawniony. Zmień elementy wewnętrzne i (b) zmieni kolor na czerwony; mając na uwadze, że (a) zmienia kolor na czerwony tylko wtedy, gdy zmiany w wewnętrznych elementach przynoszą oczekiwany wynik. (b) był moim zdaniem wyraźnie bezcelowym testem.

Jeśli masz klasę, która udostępnia kilka metod do świata zewnętrznego, właściwa rzecz do testu moim zdaniem to ostatnie metody tylko . Jeśli przetestujesz również logikę wewnętrzną, możesz w końcu ujawnić logikę wewnętrzną światu zewnętrznemu, stosując skomplikowane metody testowania lub litanię testów jednostkowych, które niezmiennie psują się, gdy chcesz coś zmienić.

Biorąc to wszystko pod uwagę, zdziwiłbym się, jeśli twój przyjaciel tak krytycznie ocenia testy jednostkowe, jak się wydaje. Raczej uznaję, że jest pragmatyczny. To znaczy, zauważył, że pisane testy jednostkowe są w większości bezcelowe w praktyce. Cytując: „testy jednostkowe są raczej komentowane niż przerabiane”. Dla mnie jest ukryta wiadomość - jeśli zwykle wymagają przeróbki, to dlatego, że mają tendencję do ssania. Przy takim założeniu następuje druga propozycja: programiści tracą mniej czasu na pisanie kodu, który trudniej jest pomylić - np. Testy integracyjne.

Jako taki nie chodzi o to, że ktoś jest lepszy lub gorszy. Tyle tylko, że łatwiej jest się pomylić, a w praktyce bardzo często się myli.


13
To sto razy to. To wielka zaleta w rozwoju opartym na testach. Najpierw napisanie testów pomoże Ci napisać testy, które nie testują szczegółów twojej implementacji, ale zamierzone zachowanie, które próbujesz wdrożyć.
wirrbel,

9
Myślę, że kruche testy jednostkowe nie są nieodłączną cechą testów jednostkowych, ale zamiast nieporozumień, do czego służą testy jednostkowe. Potrzebujemy tutaj lepszej edukacji dla programistów. Jeśli wykonasz test jednostkowy szczegółów implementacji, robisz to źle . Jeśli upublicznisz prywatne metody „w celu ich przetestowania”, robisz to źle . Zawsze testuj interfejs i zachowanie publiczne, które powinny się zmieniać rzadziej niż szczegóły implementacji!
Andres F.,

2
@DocBrown: Rzeczywiście nie. Chodzi mi o to, że tak często dzieje się to źle, że kolega z OP ma poprawkę w większości przypadków - a przynajmniej we wszystkich przypadkach, w których kiedykolwiek natknąłem się na obsesję na punkcie testów jednostkowych.
Denis de Bernardy,

3
@DenisdeBernardy: mam na myśli: wszystko, co napisałeś, jest z pewnością poprawne z dużą mądrością z praktyki, ale nie rozumiem, co to oznacza dla sprawy PO z jego kolegą, w kontekście sugestii „testów integracyjnych jako lepsza alternatywa ”.
Doc Brown,

5
Zdecydowanie zgadzam się z doktorem Brownem. Zasadniczo wydaje się, że twoje stanowisko jest takie, że testy jednostkowe są dobre, ale kiedy są źle napisane, stają się kłopotliwe. W związku z tym w ogóle nie zgadzasz się z kolegą OP, a jedynie powinieneś upewnić się, że faktycznie napisałeś testy jednostkowe przed stwierdzeniem ich przydatności. Myślę, że twoja odpowiedź jest bardzo myląca, ponieważ pierwsze zdanie mówi, że zgadzasz się ze współpracownikiem OP, kiedy wydaje się, że tak nie jest. Wygląda bardziej na rant na źle napisane testy jednostkowe (co jest problemem w praktyce, przyznaję), a nie na argument przeciwko testom jednostkowym w ogóle.
Vincent Savard

38

W przypadku poważnych zmian w kodzie testy jednostkowe są raczej komentowane niż przerabiane.

Z niezdyscyplinowaną grupą kowbojskich programistów, którzy uważają, że wszystkie testy stają się „zielone”, gdy komentujesz wszystkie istniejące testy: oczywiście. Przeróbka testów jednostkowych wymaga takiej samej dyscypliny, jak pisanie ich z pierwszej ręki, więc musisz nad tym popracować „definicję ukończenia” zespołu.

Lepiej poświęcić czas na testy integracyjne obejmujące przypadki użycia, które sprawiają, że testy o mniejszym zasięgu są mniej / wcale nie ważne.

To nie jest ani całkowicie złe, ani całkowicie właściwe. Wysiłek związany z pisaniem przydatnych testów integracyjnych zależy w dużej mierze od rodzaju tworzonego oprogramowania. Jeśli masz oprogramowanie, w którym testy integracyjne można napisać prawie tak samo łatwo, jak testy jednostkowe, działają one nadal szybko i zapewniają dobry zasięg kodu, wtedy twój kolega ma rację. Ale w wielu systemach widziałem, że te trzy punkty nie mogą być łatwo spełnione przez testy integracyjne, dlatego powinieneś starać się mieć również testy jednostkowe.


Tak bardzo się czułem, kiedy o tym rozmawialiśmy. Zakładając, że dla przypadku użycia można napisać pełne i odpowiednie testy integracyjne, wydaje się, że test jednostkowy byłby sporny. (Chociaż teraz, gdy to piszę, myślę o nieoczekiwanych przyszłych sprawach - takich jak przekształcenie naszego zaplecza w usługę sieciową dla innej aplikacji).
Jeff Levine,

+1 Za „musisz opracować swoją definicję ukończenia”. Dobrze powiedziane!
Andres F.,

14

Nie wiem, czy akceptuję argumenty twojego kolegi.

  1. Jeśli testy jednostkowe są komentowane, to dlatego, że ktoś jest leniwy. To nie wina testów jednostkowych. A jeśli zaczniesz używać leniwej wymówki, możesz argumentować przeciwko prawie każdej praktyce, która wymaga niewielkiego wysiłku.
  2. Jeśli robisz to dobrze, testy jednostkowe nie muszą trwać długo. Nie powstrzymują cię od wykonywania ważniejszej pracy. Jeśli wszyscy zgodzimy się, że naprawienie uszkodzonego kodu jest ważniejsze niż cokolwiek innego, test jednostkowy jest cholernie ważny. To łatwy sposób przetestowania warunków pocztowych. Bez tego, skąd wiesz, że spełniłeś warunki gwarancji pocztowej? A jeśli nie, kod jest uszkodzony.

Istnieją inne, bardziej przekonujące argumenty przeciwko testom jednostkowym. Nie do końca przeciwko nim. Zacznij od uszkodzeń projektowych spowodowanych przez DHH . Jest zabawnym pisarzem, więc przeczytaj to. Co z tego wziąłem:

Jeśli wprowadzisz duże zmiany projektowe w celu dostosowania testów jednostkowych, mogą one utrudnić osiągnięcie innych celów w twoim projekcie. Jeśli to możliwe, zapytaj bezstronną osobę, które podejście jest łatwiejsze do zastosowania. Jeśli Twój wysoce testowalny kod jest trudny do zrozumienia, możesz stracić wszystkie korzyści, które uzyskałeś dzięki testom jednostkowym. Nadmiar poznawczy nadmiernej abstrakcji spowalnia cię i ułatwia wyciekające błędy. Nie dyskontuj tego.

Jeśli chcesz uzyskać niuanse i filozofię, istnieje wiele wspaniałych zasobów:


+1 za ten artykuł może być lepszą odpowiedzią na sprawę PO niż wszystko, co możemy tu napisać
Doc Brown

+1 za punkt 1 o lenistwie jako wymówki. Nie mogę wystarczająco podkreślić, jak frustrujące jest to. Byłem tam. Ostatnio właściwie.
Greg Burghardt,

3
Powód 1 nie jest błędem testów jednostkowych, ale nadal jest powodem do rezygnacji z testów jednostkowych.
user253751,

Po przeczytaniu artykułu DHH koniecznie obejrzyj filmy, w których omawiał ten temat z Kentem Beckem i Martinem Fowlerem (są na youtube) - wiele osób wydaje się mieć bardziej ekstremalną wersję tego, co zamierzał, i sprecyzował to w tych dyskusjach.
Jules

6

Gdy wystąpią poważne zmiany w kodzie (nowy zestaw POJO, refaktoryzacja dużych aplikacji itp.), Testy jednostkowe są raczej komentowane niż przerabiane.

Nie rób tego Jeśli znajdziesz kogoś, kto to zrobi, zamorduj go i upewnij się, że się nie rozmnażają, ponieważ ich dzieci mogą odziedziczyć ten wadliwy gen. Kluczem, jaki widzę podczas oglądania programów telewizyjnych CSI, jest rozrzucenie wszędzie wielu wprowadzających w błąd próbek DNA. W ten sposób zanieczyszczasz miejsce zbrodni tak dużym hałasem, że biorąc pod uwagę kosztowną i czasochłonną naturę badań DNA, prawdopodobieństwo przypisania go do ciebie jest astronomicznie niskie.


4

testy jednostkowe są raczej komentowane niż przerabiane.

W tym momencie proces sprawdzania kodu mówi „idź naprawić testy jednostkowe” i to już nie jest problem :-) Jeśli proces sprawdzania kodu nie wychwytuje tego rodzaju poważnych wad w przesyłanym kodzie, to jest problem.


3

Gdy wystąpią poważne zmiany w kodzie (nowy zestaw POJO, refaktoryzacja dużych aplikacji itp.), Testy jednostkowe są raczej komentowane niż przerabiane.

Zawsze staram się trzymać osobno refaktoryzację i zmianę funkcjonalności. Kiedy muszę wykonać obie te czynności, zwykle najpierw dokonuję refaktoryzacji.

Podczas refaktoryzacji kodu bez zmiany funkcjonalności istniejące testy jednostkowe powinny pomóc upewnić się, że refaktoryzacja nie zepsuje funkcjonalności przypadkowo. Tak więc dla takiego zatwierdzenia uważam wyłączenie lub usunięcie testów jednostkowych za główny znak ostrzegawczy. Każdy programista, który to robi, powinien zostać poinformowany, aby tego nie robił podczas sprawdzania kodu.

Możliwe, że zmiany, które nie zmieniają funkcjonalności, nadal powodują niepowodzenia testów jednostkowych z powodu wadliwych testów jednostkowych. Jeśli rozumiesz zmieniany kod, to przyczyną takich niepowodzeń testu jednostkowego jest zwykle natychmiast oczywista i łatwa do naprawienia.

Na przykład, jeśli funkcja pobiera trzy argumenty, test jednostkowy obejmujący interakcję między dwoma pierwszymi argumentami dla funkcji mógł nie zadbać o podanie prawidłowej wartości trzeciego argumentu. Ta wada w teście jednostkowym może zostać ujawniona przez refaktoryzację testowanego kodu, ale łatwo go naprawić, jeśli zrozumiesz, co powinien zrobić kod i co testuje test jednostkowy.

Podczas zmiany istniejącej funkcjonalności zwykle konieczna będzie również zmiana niektórych testów jednostkowych. W takim przypadku testy jednostkowe pomagają upewnić się, że kod zmienia funkcjonalność zgodnie z przeznaczeniem i nie ma niezamierzonych skutków ubocznych.

Podczas naprawiania błędów lub dodawania nowej funkcjonalności zwykle trzeba dodać więcej testów jednostkowych. Dla tych może być pomocne najpierw zatwierdzenie testów jednostkowych, a następnie poprawka błędu lub nowa funkcjonalność później. Ułatwia to sprawdzenie, czy nowe testy jednostkowe nie przeszły ze starszym kodem, ale przeszły z nowszym kodem. Takie podejście nie jest jednak całkowicie pozbawione wad, dlatego istnieją również argumenty przemawiające za jednoczesnym przeprowadzaniem zarówno nowych testów jednostkowych, jak i aktualizacji kodu.

Lepiej poświęcić czas na testy integracyjne obejmujące przypadki użycia, dzięki którym testy o mniejszym zasięgu są mniej / wcale nie ważne.

Jest w tym pewien element prawdy. Jeśli możesz uzyskać pokrycie dolnych warstw stosu oprogramowania testami skierowanymi na wyższe warstwy stosu oprogramowania, Twoje testy mogą być bardziej pomocne podczas refaktoryzacji kodu.

Nie sądzę jednak, abyś znalazł zgodę na dokładne rozróżnienie między testem jednostkowym a testem integracyjnym. I nie martwiłbym się, jeśli masz przypadek testowy, który jeden programista nazywa testem jednostkowym, a drugi testem integracji, o ile mogą zgodzić się, że jest to przydatny przypadek testowy.


3

Testy integracyjne mają na celu sprawdzenie, czy system zachowuje się tak, jak powinien, co zawsze ma wartość biznesową. Testy jednostkowe nie zawsze to robią. Testy jednostkowe mogą na przykład polegać na testowaniu martwego kodu.

Istnieje filozofia testowania, która mówi, że każdy test, który nie zawiera informacji, jest marnotrawstwem. Kiedy fragment kodu nie jest przetwarzany, jego testy jednostkowe zawsze (lub prawie zawsze) będą zielone, dając niewiele lub żadną informację.

Każda metoda testowania będzie niekompletna. Nawet jeśli uzyskasz 100% pokrycie według niektórych danych, nadal nie przejdziesz przez prawie każdy możliwy zestaw danych wejściowych. Więc nie myśl, że testy jednostkowe są magiczne.

Często widziałem twierdzenie, że testy jednostkowe poprawiają kod. Moim zdaniem ulepszenia wprowadzone przez testy jednostkowe kodu zmuszają ludzi, którzy nie są do tego przyzwyczajeni, do dzielenia kodu na małe, dobrze przemyślane elementy. Jeśli przyzwyczaisz się do projektowania kodu w małych, dobrze przemyślanych fragmentach, może się okazać, że nie potrzebujesz testów jednostkowych, aby zmusić Cię do tego.

W zależności od tego, jak ciężko przeprowadzasz testy jednostkowe i jak duży jest twój program, możesz skończyć z ogromną ilością testów jednostkowych. Jeśli tak, duże zmiany stają się trudniejsze. Jeśli duża zmiana powoduje wiele nieudanych testów jednostkowych, możesz odmówić jej wprowadzenia, wykonać wiele pracy, aby naprawić wiele testów lub je wyrzucić. Żaden wybór nie jest idealny.

Testy jednostkowe są narzędziem w przyborniku. Są po to, aby ci służyć, a nie na odwrót. Upewnij się, że wydostaniesz się z nich przynajmniej tyle, ile włożysz.


3

Testy jednostkowe zdecydowanie nie są srebrną kulą, jak twierdzą niektórzy zwolennicy. Ale ogólnie mają one bardzo pozytywny stosunek kosztów do korzyści. Nie sprawią, że Twój kod będzie „lepszy”, może bardziej modułowy. „lepszy” ma o wiele więcej czynników niż implikuje „testowalność”. Ale zapewnią, że zadziała we wszystkich przypadkach i zastosowaniach, o których myślałeś, i wyeliminują większość twoich błędów (prawdopodobnie najbardziej trywialnych).

Największą zaletą testów jednostkowych jest to, że zwiększają elastyczność kodu i są odporne na zmiany. Możesz zmienić lub dodać funkcje i mieć całkowitą pewność, że niczego nie zepsułeś. Już to sprawia, że ​​są one opłacalne w przypadku większości projektów.

Odnosząc się do punktów przedstawionych przez twojego przyjaciela:

  1. Jeśli dodanie POJO przerwie testy jednostkowe, prawdopodobnie są one bardzo źle napisane. POJO to zwykle język, którego używasz do mówienia o swojej domenie, a problemy, które rozwiązujesz, ich zmiana oczywiście oznacza całą logikę biznesową i prawdopodobnie kod prezentacji musi się zmienić. Nie możesz oczekiwać, że to, co zapewnia, że ​​te części twojego programu nie zmienią się ...

  2. Narzekanie, że testy jednostkowe są złe, ponieważ ludzie je komentują, jest jak narzekanie na pasy bezpieczeństwa, ponieważ ludzie ich nie noszą. Jeśli ktoś komentuje testowanie kodu i coś psuje, powinien zakończyć bardzo poważną i nieprzyjemną rozmowę z szefem ...

  3. Testy integracyjne znacznie przewyższają testy jednostkowe. bez pytania. szczególnie jeśli testujesz produkt. Ale napisanie dobrych, kompleksowych testów integracyjnych, które zapewnią taką samą wartość, zakres i pewność poprawności, jakie dają testy jednostkowe, jest niezwykle trudne.


2

Mogę wymyślić tylko jeden argument przeciwko testom jednostkowym i jest on dość słaby.

Testy jednostkowe pokazują większość ich wartości, gdy dokonamy refaktoryzacji lub zmiany kodu na późniejszym etapie. Widzisz ogromną redukcję czasu potrzebnego do dodania funkcji i upewnienia się, że niczego nie zepsułeś.

Jednak: Przede wszystkim jest (niewielki) koszt pisania testów.

Dlatego: jeśli projekt jest wystarczająco krótki i nie wymaga ciągłej konserwacji / aktualizacji, możliwe jest, że koszt pisania testów przewyższy ich korzyści.


+1 za próbę rzetelnej odpowiedzi na zadane pytanie.
RubberDuck,

2
Koszt testu jednostkowego nie jest zdecydowanie niewielki. Dobre testy jednostkowe zwykle wymagają więcej czasu niż napisanie. W większości przypadków korzyści przewyższają koszty.
AK_

1
tylko w teorii - gdy dokonujesz refaktoryzacji, kończysz się ogromnym kosztem aktualizacji testów jednostkowych, ponieważ prawie zawsze są one zbyt szczegółowe. Jeśli mówiłeś o dobrym pakiecie testów integracji, miałbyś rację.
gbjbaanb,

Jeśli projekt jest wystarczająco krótki i nie wymaga ciągłej konserwacji / aktualizacji - większość starszych systemów zaczęła się jako krótki projekt bez testów - i kończy się na zatrudnianiu większej liczby programistów do obsługi rozwiniętego systemu bez testów
Fabio
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.