JavaRush /Blog Java /Random-PL /Co to jest TDD i testy jednostkowe [tłumaczenie]
Dr-John Zoidberg
Poziom 41
Марс

Co to jest TDD i testy jednostkowe [tłumaczenie]

Opublikowano w grupie Random-PL
Ten artykuł jest adaptacją rozdziału z książki The Complete Software Career Guide. Pisze ją jej autor, John Sonmez, a niektóre rozdziały zamieszcza na swojej stronie internetowej.
Co to jest TDD i testy jednostkowe [tłumaczenie] - 1

Krótki słowniczek dla początkujących

Testowanie jednostkowe lub testowanie jednostkowe to proces w programowaniu, który pozwala sprawdzić poprawność poszczególnych modułów kodu źródłowego programu. Pomysł jest taki, aby pisać testy dla każdej nietrywialnej funkcji lub metody. Testowanie regresyjne to ogólna nazwa wszystkich rodzajów testów oprogramowania mających na celu wykrycie błędów w już przetestowanych obszarach kodu źródłowego. Błędy takie – gdy po wprowadzeniu zmian w programie coś, co powinno dalej działać przestaje działać – nazywane są błędami regresyjnymi. Wynik czerwony, niepowodzenie - niepowodzenie testu. Różnica między oczekiwanym wynikiem a rzeczywistym. Wynik zielony, pozytywny - pozytywny wynik testu. Rzeczywisty wynik nie różni się od uzyskanego. ***
Co to jest TDD i testy jednostkowe [tłumaczenie] - 2
Mam bardzo mieszane podejście do rozwoju opartego na testach (TDD) i testów jednostkowych, przechodząc od miłości do nienawiści i z powrotem. Byłem zagorzałym fanem i jednocześnie podejrzliwym sceptykiem co do stosowania tej i innych „najlepszych praktyk”. Powodem mojej postawy jest fakt, że w procesach wytwarzania oprogramowania pojawił się poważny problem: programiści, a czasami menedżerowie, korzystają z pewnych narzędzi i metodologii tylko dlatego, że należą one do „najlepszych praktyk”. Prawdziwy powód ich stosowania pozostaje niejasny. Któregoś dnia zacząłem pracować nad pewnym projektem i przy okazji zostałem poinformowany, że będziemy modyfikować kod objęty ogromną liczbą testów jednostkowych. To nie żart, było ich około 3000. To zazwyczaj dobry znak, sygnał, że twórcy korzystają z zaawansowanych metodologii. Kod przy takim podejściu jest najczęściej ustrukturyzowany i opiera się na przemyślanej architekturze. Jednym słowem obecność testów bardzo mnie ucieszyła, choćby dlatego, że ułatwiła mi pracę jako mentora programistów. Ponieważ mieliśmy już testy jednostkowe, jedyne, co musiałem zrobić, to podłączyć zespół programistów do ich wsparcia i zacząć pisać własny kod. Otworzyłem IDE (zintegrowane środowisko programistyczne) i załadowałem projekt.
Co to jest TDD i testy jednostkowe [tłumaczenie] - 3
To był duży projekt! Znalazłem folder o nazwie „testy jednostkowe”. „Świetnie” – pomyślałem. - Uruchommy to i zobaczmy, co się stanie. Zajęło to tylko kilka minut i ku mojemu zdziwieniu wszystkie testy przeszły pomyślnie, wszystko było zielone ( „zielony” to pozytywny wynik testu. Sygnalizuje, że kod działa zgodnie z oczekiwaniami. Kolor czerwony oznacza „niepowodzenie” lub niepowodzenie, wówczas zdarza się, że kod nie działa poprawnie – przyp. tłumacza ). Wszyscy przeszli test. W tym momencie obudził się we mnie sceptyk. Jak to się stało, że trzy tysiące testów jednostkowych, a oni wzięli je wszystkie na raz - i dali wynik pozytywny? W mojej długiej praktyce nie pamiętam chwili, kiedy zaczynałem pracę nad projektem bez ani jednego negatywnego testu jednostkowego w kodzie. Co robić? Sprawdź ręcznie! ChY wybrał jeden losowy test, niezbyt odkrywczy, ale od razu stało się jasne, co sprawdza. Ale w trakcie pracy zauważyłem coś absurdalnego: test nie zawierał żadnych porównań z oczekiwanym wynikiem (twierdzeń)! Oznacza to, że w rzeczywistości nic nie zostało sprawdzone ! W teście były pewne etapy, zostały wykonane, ale pod koniec testu, gdzie należało porównać wyniki rzeczywiste i oczekiwane, nie było żadnej kontroli. „Test” niczego nie testował. Otworzyłem kolejny test. Jeszcze lepiej: operator porównania z wynikiem został wykomentowany. Błyszcząco! To świetny sposób na wykonanie testu. Wystarczy, że skomentujesz kod, który powoduje jego niepowodzenie. Sprawdziłem kolejny test, potem kolejny... Żaden z nich niczego nie sprawdził. Trzy tysiące testów i wszystkie są całkowicie bezużyteczne. Istnieje ogromna różnica pomiędzy pisaniem testów jednostkowych a zrozumieniem testów jednostkowych i programowania sterowanego testami (TDD).

Co to są testy jednostkowe?

Co to jest TDD i testy jednostkowe [tłumaczenie] - 4
Podstawową ideą testów jednostkowych jest pisanie testów testujących najmniejszą „jednostkę” kodu. Testy jednostkowe są zwykle pisane w tym samym języku programowania, co kod źródłowy aplikacji. Są tworzone bezpośrednio w celu przetestowania tego kodu. Oznacza to, że testy jednostkowe to kod sprawdzający poprawność innego kodu. Używam słowa „test” w kontekście dość swobodnie, ponieważ testy jednostkowe w pewnym sensie nie są testami. Nie doświadczają niczego. Mam na myśli to, że kiedy przeprowadzasz test jednostkowy, zwykle nie stwierdzasz, że jakiś kod nie działa. Odkrywasz to podczas pisania testu, ponieważ będziesz zmieniać kod, aż test zmieni kolor na zielony. Tak, kod może zmienić się później i wtedy test może się nie powieść. W tym sensie test jednostkowy jest testem regresji. Test jednostkowy nie przypomina zwykłego testu, w którym masz kilka kroków, które należy wykonać i sprawdzić, czy oprogramowanie działa poprawnie, czy nie. Podczas pisania testu jednostkowego odkrywasz, czy kod robi to, co powinien, czy nie, i będziesz go zmieniać, dopóki test nie zakończy się pomyślnie.
Co to jest TDD i testy jednostkowe [tłumaczenie] - 5
Dlaczego nie napisać testu jednostkowego i sprawdzić, czy przejdzie? Jeśli tak o tym pomyśleć, to testy jednostkowe zamieniają się w pewnego rodzaju wymagania bezwzględne dla określonych modułów kodu na bardzo niskim poziomie. Test jednostkowy można traktować jako specyfikację absolutną . Test jednostkowy określa, że ​​w tych warunkach, przy tym konkretnym zestawie danych wejściowych, istnieje wynik, który powinien zostać uzyskany z tej jednostki kodu. Prawdziwe testy jednostkowe identyfikują najmniejszą spójną jednostkę kodu, którą w większości języków programowania – przynajmniej obiektowych – jest klasa.

Co czasami nazywa się testowaniem jednostkowym?

Co to jest TDD i testy jednostkowe [tłumaczenie] - 6
Testy jednostkowe są często mylone z testami integracyjnymi. Niektóre „testy jednostkowe” testują więcej niż jedną klasę lub testują duże jednostki kodu. Wielu programistów twierdzi, że pisze testy jednostkowe, podczas gdy w rzeczywistości piszą niskopoziomowe testy typu whitebox. Nie kłóć się z tymi facetami. Po prostu wiedz, że tak naprawdę piszą testy integracyjne, a prawdziwe testy jednostkowe testują najmniejszą jednostkę kodu w izolacji od innych części. Inną rzeczą często nazywaną testowaniem jednostkowym są testy jednostkowe bez sprawdzania wartości oczekiwanej. Innymi słowy, testy jednostkowe, które w rzeczywistości niczego nie testują. Każdy test, ujednolicony lub nie, musi zawierać pewnego rodzaju weryfikację - nazywamy to sprawdzeniem rzeczywistego wyniku w stosunku do oczekiwanego wyniku. To właśnie to pojednanie decyduje o tym, czy test zakończy się pomyślnie, czy nie. Test, który zawsze przechodzi pomyślnie, jest bezużyteczny. Test, który zawsze kończy się niepowodzeniem, jest bezużyteczny.

Wartość testów jednostkowych

Dlaczego jestem entuzjastą testów jednostkowych? Dlaczego nazywanie testowania uogólnionego, które polega na testowaniu nie najmniejszego bloku wyizolowanego z innego kodu, ale większego fragmentu kodu, „testowaniem jednostkowym” jest szkodliwe? Jaki jest problem, jeśli niektóre z moich testów nie porównują otrzymanych wyników z oczekiwanymi? Przynajmniej wykonują kod. Spróbuję wyjaśnić.
Co to jest TDD i testy jednostkowe [tłumaczenie] - 7
Istnieją dwa główne powody przeprowadzania testów jednostkowych. Pierwszym z nich jest ulepszenie projektu kodu. Pamiętasz, jak mówiłem, że testy jednostkowe tak naprawdę nie są testowaniem? Kiedy piszesz odpowiednie testy jednostkowe, zmuszasz się do wyizolowania najmniejszej jednostki kodu. Próby te doprowadzą Cię do odkrycia problemów w strukturze samego kodu. Może się okazać, że bardzo trudno będzie wyizolować klasę testową i nie uwzględnić jej zależności, co może uświadomić sobie, że kod jest zbyt ściśle powiązany. Może się okazać, że podstawowa funkcjonalność, którą próbujesz przetestować, obejmuje wiele modułów, co doprowadzi Cię do przekonania, że ​​Twój kod nie jest wystarczająco spójny. Kiedy siadasz do napisania testu jednostkowego, możesz nagle odkryć (i wierz mi, to się zdarza!), że nie masz pojęcia, co kod ma robić. W związku z tym nie będzie można napisać dla niego testu jednostkowego. I oczywiście możesz znaleźć prawdziwy błąd w implementacji kodu, ponieważ test jednostkowy zmusza Cię do myślenia nieszablonowego i testowania różnych zestawów danych wejściowych, których być może nie brałeś pod uwagę.
Co to jest TDD i testy jednostkowe [tłumaczenie] - 8
Jeśli podczas tworzenia testów jednostkowych będziesz ściśle przestrzegać zasady „testuj najmniejszą jednostkę kodu w izolacji od innych”, z pewnością znajdziesz najróżniejsze problemy z tym kodem i projektem tych modułów. W cyklu życia oprogramowania testy jednostkowe są bardziej działaniem oceniającym niż testującym. Drugim głównym celem testów jednostkowych jest stworzenie zautomatyzowanego zestawu testów regresyjnych, które mogą działać jako niskopoziomowa specyfikacja zachowania oprogramowania. Co to znaczy? Zagniatając ciasto, nie łamiemy go. Z tego punktu widzenia testy jednostkowe są testami, a dokładniej testami regresyjnymi. Celem testów jednostkowych nie jest jednak proste zbudowanie testów regresyjnych. W praktyce testy jednostkowe rzadko wychwytują regresje, ponieważ zmiana testowanej jednostki kodu prawie zawsze wiąże się ze zmianami w samym teście jednostkowym. Testowanie regresyjne jest znacznie skuteczniejsze na wyższym poziomie, gdy kod jest testowany jako „czarna skrzynka”, ponieważ na tym poziomie można zmienić wewnętrzną strukturę kodu, podczas gdy oczekuje się, że zachowanie zewnętrzne pozostanie takie samo. Testy jednostkowe z kolei sprawdzają strukturę wewnętrzną, aby w przypadku zmiany tej struktury testy jednostkowe nie zawiodły. Stają się bezużyteczne i teraz trzeba je zmienić, wyrzucić lub napisać na nowo. Wiesz teraz więcej o prawdziwym celu testów jednostkowych niż wielu doświadczonych programistów.

Co to jest rozwój oparty na testach (TDD)?

Co to jest TDD i testy jednostkowe [tłumaczenie] - 9
W procesie tworzenia oprogramowania dobra specyfikacja jest na wagę złota. Podejście TDD polega na tym, że zanim napiszesz jakikolwiek kod, najpierw napisz test, który posłuży jako specyfikacja, czyli zdefiniuj, co kod powinien robić. Jest to niezwykle skuteczna koncepcja tworzenia oprogramowania, ale często jest niewłaściwie wykorzystywana. Zazwyczaj programowanie oparte na testach oznacza używanie testów jednostkowych do kierowania tworzeniem kodu aplikacji. Ale w rzeczywistości podejście to można zastosować na dowolnym poziomie. Jednak w tym artykule założymy, że w naszej aplikacji używamy testów jednostkowych. Podejście TDD stawia wszystko na głowie i zamiast najpierw pisać kod, a potem testy jednostkowe w celu przetestowania tego kodu, najpierw piszesz test jednostkowy, a następnie kod, który sprawi, że test będzie zielony. W ten sposób testy jednostkowe „napędzają” rozwój kodu. Proces ten powtarza się wielokrotnie. Piszesz kolejny test, który definiuje większą funkcjonalność tego, co powinien robić kod. Następnie piszesz i modyfikujesz kod, aby upewnić się, że test zakończył się pomyślnie. Gdy uzyskasz zielony wynik, rozpoczynasz refaktoryzację kodu, to znaczy refaktoryzację lub czyszczenie go, aby był bardziej zwięzły. Ten łańcuch procesów jest często nazywany „refaktoryzacją czerwono-zieloną”, ponieważ najpierw test jednostkowy kończy się niepowodzeniem (czerwony), następnie pisany jest kod, aby dostosować się do testu i upewnić się, że się powiedzie (zielony), a na koniec kod jest zoptymalizowany ( refaktoryzacja).

Jaki jest cel TDD?

Co to jest TDD i testy jednostkowe [tłumaczenie] - 10
Rozwój oparty na testach (TDD), podobnie jak testy jednostkowe, może być niewłaściwie używany. Bardzo łatwo jest nazwać to, co robisz, „TDD”, a nawet postępować zgodnie z praktyką, nie rozumiejąc, dlaczego robisz to w ten sposób. Największą wartością TDD jest to, że przeprowadzane są testy w celu uzyskania specyfikacji jakości. TDD to zasadniczo praktyka pisania precyzyjnych specyfikacji, które można automatycznie sprawdzić przed napisaniem kodu. Testy są najlepszą specyfikacją, ponieważ nie kłamią. Nie powiedzą Ci po dwóch tygodniach męki z kodem „nie o to mi chodziło”. Testy, jeśli są napisane poprawnie, albo zaliczają się, albo nie. Testy jasno wskazują, co powinno się wydarzyć w określonych okolicznościach. Zatem celem TDD jest pełne zrozumienie tego, co musimy wdrożyć, zanim zaczniemy to wdrażać. Jeśli zaczynasz od TDD i nie wiesz, co test ma testować, musisz zadać więcej pytań. Inną ważną rolą TDD jest zachowanie i optymalizacja kodu. Utrzymanie kodu jest kosztowne. Często żartuję, że najlepszym programistą jest ten, który pisze najkrótszy kod rozwiązujący jakiś problem. Lub nawet taki, który udowodni, że tego problemu nie trzeba rozwiązywać, a tym samym całkowicie usuwa kod, ponieważ to właśnie ten programista znalazł właściwy sposób na zmniejszenie liczby błędów i zmniejszenie kosztów utrzymania aplikacji. Używając TDD, możesz być absolutnie pewien, że nie piszesz niepotrzebnego kodu, ponieważ będziesz pisać kod tylko po to, aby przejść testy. Istnieje zasada tworzenia oprogramowania zwana YAGNI (nie będziesz jej potrzebować). TDD zapobiega YAGNI.

Typowy przepływ pracy w zakresie programowania opartego na testach (TDD).

Co to jest TDD i testy jednostkowe [tłumaczenie] - 11
Zrozumienie znaczenia TDD z czysto akademickiego punktu widzenia jest trudne. Spójrzmy więc na przykład sesji TDD. Wyobraź sobie, że siadasz przy biurku i szybko szkicujesz zaawansowany projekt funkcji umożliwiającej użytkownikowi zalogowanie się do aplikacji i zmianę hasła, jeśli je zapomni. Decydujesz, że zaczniesz od pierwszej implementacji funkcji logowania, tworząc klasę, która zajmie się całą logiką procesu logowania. Otwierasz swój ulubiony edytor i tworzysz test jednostkowy o nazwie „Puste logowanie uniemożliwia użytkownikowi zalogowanie się”. Piszesz kod testu jednostkowego, który najpierw tworzy instancję klasy Login (której jeszcze nie utworzyłeś). Następnie piszesz kod wywołujący metodę w klasie Login, która przekazuje pustą nazwę użytkownika i hasło. Na koniec napiszesz sprawdzenie oczekiwanego wyniku, sprawdzając, czy użytkownik z pustym loginem faktycznie nie jest zalogowany. Próbujesz uruchomić test, ale nawet się nie kompiluje, ponieważ nie masz klasy Login. Naprawiasz tę sytuację i tworzysz klasę Login wraz z metodą w tej klasie do logowania i inną, która sprawdza status użytkownika i sprawdza, czy jest zalogowany. Jak dotąd nie zaimplementowałeś funkcjonalności tej klasy i metody, której potrzebujemy. W tym momencie uruchamiasz test. Teraz się kompiluje, ale natychmiast kończy się niepowodzeniem.
Co to jest TDD i testy jednostkowe [tłumaczenie] - 12
Teraz wracasz do kodu i implementujesz funkcjonalność, aby przejść test. W naszym przypadku oznacza to, że powinniśmy otrzymać wynik: „użytkownik nie jest zalogowany”. Uruchamiasz test ponownie i teraz przechodzi. Przejdźmy do następnego testu. Teraz wyobraźmy sobie, że musisz napisać test o nazwie „Użytkownik jest zalogowany, jeśli podał prawidłową nazwę użytkownika i hasło”. Piszesz test jednostkowy, który tworzy instancję klasy Login i próbuje zalogować się przy użyciu nazwy użytkownika i hasła. W teście jednostkowym piszesz stwierdzenie, że klasa Login powinna odpowiedzieć twierdząco na pytanie, czy użytkownik jest zalogowany. Uruchamiasz ten nowy test i oczywiście kończy się on niepowodzeniem, ponieważ klasa Login zawsze zwraca informację, że użytkownik nie jest zalogowany. Wracasz do klasy Login i implementujesz kod, aby sprawdzić, czy użytkownik jest zalogowany. W takim przypadku będziesz musiał dowiedzieć się, jak odizolować ten moduł. Na razie najłatwiej to zrobić, wpisując na stałe nazwę użytkownika i hasło użyte w teście, a jeśli są zgodne, zwróć wynik „użytkownik jest zalogowany”. Wprowadzasz tę zmianę, uruchamiasz oba testy i oba przechodzą pomyślnie. Przejdźmy do ostatniego kroku: patrzysz na wygenerowany kod i szukasz sposobu na jego reorganizację i uproszczenie. Zatem algorytm TDD wygląda następująco:
  1. Utworzono test.
  2. Napisaliśmy kod do tego testu.
  3. Zrefaktoryzowano kod.

wnioski

Co to jest TDD i testy jednostkowe [tłumaczenie] - 13
To wszystko, co chciałem powiedzieć na tym etapie o testach jednostkowych i TDD. W rzeczywistości istnieje wiele trudności związanych z próbą izolowania modułów kodu, ponieważ kod może być bardzo złożony i zagmatwany. Bardzo niewiele klas istnieje w całkowitej izolacji. Zamiast tego mają zależności, a te zależności mają zależności i tak dalej. Aby sobie poradzić z takimi sytuacjami, weteran TDD używa makiet, które pomagają izolować poszczególne klasy poprzez zastępowanie obiektów w zależnych modułach. Ten artykuł jest jedynie przeglądem i nieco uproszczonym wprowadzeniem do testów jednostkowych i TDD, nie będziemy wdawać się w szczegóły na temat fikcyjnych modułów i innych technik TDD. Chodzi o to, aby dać ci podstawowe pojęcia i zasady TDD i testów jednostkowych, które, mam nadzieję, już znasz. Oryginał - https://simpleprogrammer.com/2017/01/30/tdd-unit-testing/
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION