Nie jestem nowy w kodowaniu. Koduję (poważnie) od ponad 15 lat. Zawsze miałem jakieś testy dla mojego kodu. Jednak w ciągu ostatnich kilku miesięcy uczyłem się projektowania / rozwoju opartego na testach (TDD) przy użyciu Ruby on Rails . Jak dotąd nie widzę korzyści.
Widzę pewne korzyści z pisania testów dla niektórych rzeczy, ale bardzo niewiele. I chociaż podoba mi się pomysł napisania testu jako pierwszego, okazuje się, że spędzam znacznie więcej czasu próbując debugować moje testy, aby powiedzieć im to, co naprawdę mam na myśli, niż debugowanie faktycznego kodu. Jest to prawdopodobnie spowodowane tym, że kod testowy jest często znacznie bardziej skomplikowany niż kod testowany. Mam nadzieję, że jest to po prostu brak doświadczenia z dostępnymi narzędziami ( w tym przypadku RSpec ).
Muszę jednak powiedzieć, że poziom frustracji zmieszany z rozczarowującym brakiem wydajności jest nie do przyjęcia. Jak dotąd jedyną wartością, którą widzę z TDD, jest rosnąca biblioteka plików RSpec, które służą jako szablony dla innych projektów / plików. Co nie jest dużo bardziej przydatne, może mniej przydatne, niż rzeczywiste pliki kodu projektu.
Czytając dostępną literaturę, zauważam, że TDD wydaje się być ogromnym opóźnieniem, ale ostatecznie się opłaca. Zastanawiam się tylko, czy są jakieś przykłady z prawdziwego świata? Czy ta ogromna frustracja kiedykolwiek się opłaca w prawdziwym świecie?
Naprawdę mam nadzieję, że nie przegapiłem tego pytania gdzie indziej tutaj. Szukałem, ale wszystkie pytania / odpowiedzi mają kilka lat. To była rzadka okazja, kiedy znalazłem programistę, który powiedziałby coś złego o TDD, dlatego spędziłem na tym tyle samo czasu, co ja. Zauważyłem jednak, że nikt nie wskazuje na konkretne przykłady z prawdziwego świata. Przeczytałem jedną odpowiedź, która powiedziała, że facet debugujący kod w 2011 roku byłby wdzięczny za posiadanie kompletnego pakietu testów jednostkowych (myślę, że komentarz został opublikowany w 2008 roku).
Zastanawiam się, po tylu latach, czy w końcu mamy jakieś przykłady pokazujące, że wypłata jest prawdziwa? Czy ktoś faktycznie odziedziczył lub wrócił do kodu, który został zaprojektowany / opracowany przy użyciu TDD i ma pełny zestaw testów jednostkowych i faktycznie odczuł korzyści? A może odkryłeś, że spędzasz tyle czasu próbując dowiedzieć się, co testuje test (i dlaczego to było ważne), że po prostu rzuciłeś cały bałagan i wkopałeś się w kod?
źródło
Odpowiedzi:
Niniejszy dokument pokazuje, że TDD wydłuża czas rozwoju o 15–35% w zamian za zmniejszenie gęstości defektów o 40–90% w przypadku projektów podobnych do podobnych.
Artykuł odnosi się do pełnego tekstu (pdf) - Nachiappan Nagappan, E. Michael Maximilien, Thirumalesh Bhat i Laurie Williams. „Uzyskiwanie poprawy jakości dzięki rozwojowi opartemu na testach: wyniki i doświadczenia czterech zespołów przemysłowych”. ESE 2008 .
Pełny artykuł również krótko podsumowuje odpowiednie badania empiryczne dotyczące TDD i ich wyniki na wysokim poziomie (sekcja 3 Powiązane prace ), w tym George i Williams 2003, Müller i Hagner (2002), Erdogmus i in. (2005), Müller and Tichy (2001), Janzen and Seiedian (2006).
źródło
Pracuję w TDD przez ostatnie trzy lata, a moje doświadczenie jest dokładnie odwrotne. Spędzam mniej czasu na pisaniu testów jednostkowych, niż debugowanie kodu, gdybym nie napisał testów jednostkowych.
Nie tylko robię TDD, pracuję na zewnątrz, tzn. Najpierw implementuję TDD warstwy górnej / gui. Wdrożenie górnej warstwy określa wymagania dla następnej warstwy w systemie, którą opracowuję za pomocą TDD itp., Dopóki cały kod wymagany dla tej funkcji nie zostanie zaimplementowany. Często zdarza mi się, że po zaimplementowaniu takiej funkcji i testowaniu tej funkcji w rzeczywistym systemie palę, działa ona po raz pierwszy. Nie cały czas, ale często.
Biorąc pod uwagę, że testowanie funkcji w rzeczywistym systemie zajmuje dużo więcej czasu niż wykonanie kilku testów jednostkowych, oszczędzam ogromną ilość czasu. W rzeczywistości szybsze jest dla mnie zaimplementowanie funkcji przy użyciu TDD, niż w ogóle zaimplementowanie funkcji niepiszącej testów jednostkowych.
Ale pisanie testów jednostkowych jest umiejętnością, której należy się nauczyć i opanować, tak jak każdą inną umiejętność programowania. Kiedy zacząłem robić TDD, miałem 12 lat doświadczenia zawodowego w programowaniu i byłem bardzo utalentowanym programistą. Myślałem, że pisanie dużych pakietów testowych dla kodu systemowego byłoby prostą rzeczą. Ale gdy ilość kodu testowego rosła, a różne części systemu ulegały zmianie, a istniejące testy musiały zostać zmodyfikowane, dowiedziałem się, że testowanie struktur i pisanie jednostek jest samo w sobie umiejętnością, którą należy się nauczyć. Również nie cały kod jest w równym stopniu testowalny. Kod systemu musi być bardzo luźno sprzężony, aby mógł być skutecznie testowany. Właściwie nauka TDD pomogła mi luźniej powiązać kod systemu.
Ale moja obecna wydajność w pracy TDD wynika z połączenia zarówno opanowania sposobu pisania testów jednostkowych, jak i opanowania technologii, w której system jest zaimplementowany (w tym przypadku C #).
Wykonywanie TDD podczas nauki nowej technologii może być trudne, np. Chociaż trochę programowałem na iPhonie, nie piszę znacznej liczby testów jednostkowych, ponieważ nie opanowałem języka, celu c ani nie opanowałem Biblioteka. Więc nie mam pojęcia, jak ustrukturyzować moje testy jednostkowe, a tym bardziej, jak ustrukturyzować kod systemu, jak uczynić go testowalnym.
Przy projekcie, nad którym pracowałem przez ostatnie kilka lat, chociaż istnieje wymóg, aby kod był wystarczająco objęty testami jednostkowymi, jestem jedynym w zespole, który pisze testy jako pierwszy. Ale duży pakiet testowy daje mi pewność, że mogę refaktoryzować system i mam wiarę, że system będzie działał poprawnie, jeśli pakiet testowy przejdzie pomyślnie.
Ale niestety, ponieważ wiele testów jest zapisywanych po kodzie systemowym, sporo samych testów jest wadliwych, tzn. Nie testują one dokładnie tego, co miały przetestować. Tego imho nie da się uniknąć. Za każdym razem, gdy piszesz fragment kodu, istnieje prawdopodobieństwo, że kod nie będzie działał zgodnie z przeznaczeniem, tzn. Wystąpił błąd. To samo dotyczy kodu testowego. Dlatego istnieje prawdopodobieństwo, że napiszesz test, który przejdzie pomyślnie, mimo że kod, który powinien być testowany, nie działa zgodnie z przeznaczeniem.
Najpierw pisząc test, sprawdzając nie tylko to, czy test się nie powiódł, ale też, że test kończy się niepowodzeniem z dokładnie oczekiwanym komunikatem o błędzie przed zaimplementowaniem kodu systemowego poważnie zmniejsza ryzyko błędu w kodzie testu jednostkowego.
Podsumowując, z mojego doświadczenia, gdy opanujesz sztukę TDD, nie tylko zaoszczędzisz czas na dłuższą metę, ale zaoszczędzisz czas z góry. Ale opanowanie sztuki TDD wymaga czasu nawet doświadczonego programisty. Jeszcze więcej czasu zajmuje zespołowi programistów o różnych umiejętnościach opanowanie sztuki TDD.
źródło
Jesteśmy sprzedawcą 1 poziomu, co oznacza, że przetwarzamy ponad sześć milionów transakcji płatniczych rocznie.
Nasz system bramek płatności zawiera tysiące testów jednostkowych i integracyjnych. Testy te dają nam pewność co do naszej zdolności do przetwarzania płatności. Chcesz mieć pewność, że hamulce samochodu działają, prawda? Chcemy mieć pewność, że nie stracimy naszej działalności, ponieważ nie możemy przetwarzać płatności.
Pokrycie kodu daje ci pewność. Oczywiście samo w sobie nie wystarczy, ale to bardzo dobry początek.
Większość naszego systemu bramek płatniczych została napisana przy użyciu TDD. Niektóre aspekty były raczej trudne do przetestowania, dlatego postanowiliśmy skrócić rogi, poświęcając trochę kodu. W końcu wrócimy i rozwiążemy te problemy.
Osobiście trudno mi napisać logikę przed napisaniem testów. Powiedziawszy to, zajęło mi trochę czasu, aby zacząć myśleć w sposób TDD.
Dokumentacja Visa PCI: http://usa.visa.com/merchants/risk_management/cisp_merchants.html
źródło
Chociaż testy mogą być przez niektórych uważane za sposób na zrobienie zbyt wiele, wydaje mi się, że w niektórych przypadkach naprawdę warto spróbować.
Opracowuję Killer Sudoku Solver dla szkoły od około 3 miesięcy, używa wielu „strategii” do usuwania możliwości i rozwiązań. Faktem jest, że błąd w możliwości może być śmiertelny i powodować problem z rozwiązywaniem sudoku, ponieważ po usunięciu jakiejś możliwości nie próbujesz jej więcej, a jeśli to było rozwiązanie, program nie może rozwiązać siatka już.
Ale naprawdę trudno jest ręcznie przetestować, mam na myśli, że jest siatka, widzę, które strategie robią to, co w przykładzie z prawdziwego świata, ale po prostu nie mogę sprawdzić wszystkich za każdym razem, gdy strategia się stosuje, ponieważ reprezentuje to zbyt dużo danych.
A strategie stosowane na określonej siatce są dość „losowe”, to znaczy, że nie użyjesz wszystkich na określonej siatce.
Więc napisałem testy dla każdej strategii, sprawdzając wynik w każdej komórce, używając prostych sytuacji (na przykład tylko dwie komórki już usunęły możliwości) i zaoszczędziło mi to godzin dziennie, gdy niestety miałem siatkę, której nie można rozwiązać. Ponieważ już wiedziałem, gdzie jest problem.
źródło
Zaletą jest to, że TDD dowiedzieć się, jak nazywają swój kod przed zapisu rzeczywisty kod.
Innymi słowy, TDD pomaga w projektowaniu interfejsu API.
Z mojego doświadczenia wynika, że daje to lepsze interfejsy API, co z kolei daje lepszy kod.
EDYCJA: Jak pisałem, było to „z mojego doświadczenia”, tj. Podczas pisania „projektów ze świata rzeczywistego”, ale niestety dzieje się tak przy zamkniętej bazie kodu źródłowego, której nie mogę pozwolić światu zobaczyć. Mogę zrozumieć, z komentarzami, że to jest to, co faktycznie poprosił o, a nie tylko potwierdzeniem samo istnienie takich projektów.
Odkryłem również - ponownie z mojego osobistego doświadczenia - że rzeczywista korzyść pokazuje się po przejściu w tryb konserwacji, ponieważ wymagania mają tendencję do zmiany. Czystsze interfejsy API znacznie ułatwiły wyrażenie nowych lub zmienionych wymagań w kodzie testowym, a wszystkie testy bardzo ułatwiają przyszłemu opiekunowi, jak należy wywoływać kod i czego można się spodziewać.
W przypadkach testowych działają wersje specyfikacji i pozwala bardzo, bardzo łatwo zobaczyć, jak wywołać interfejs API. Jest to chyba najbardziej użyteczna forma dokumentacji „JAK” , jaką do tej pory widziałem (porównaj z dokumentacją „DLACZEGO” jak JavaDoc), ponieważ masz pewność, że jest poprawna (w przeciwnym razie test się nie powiedzie).
Ostatnio musiałem obsługiwać skryptowego klienta ftp z bardzo dużym zestawem opcji, które wpływają na działanie aplikacji. Niedawno wprowadzono TDD dla nowej funkcjonalności, a duży pakiet testowy pozwala nam robić poprawki, mając pewność, że używana funkcjonalność nadal działa zgodnie z oczekiwaniami. Innymi słowy, przejście to okazało się bardzo szybkie.
źródło
To, jak cenne jest konkretne podejście do testowania, zależy od tego, jak krytyczny jest opracowywany system i jak bardzo zależy od niego inny system o krytycznym znaczeniu. Prostego skryptu księgi gości dla Twojej witryny nie można uznać za kluczowy dla misji, ale jeśli witryna, na której działa, może zostać zagrożona przez błąd, który umożliwił niefiltrowane dane wejściowe do bazy danych, a strona ta oferuje pewną istotną usługę, nagle staje się znacznie bardziej ważne, aby skrypt księgi gości został dokładnie przetestowany. To samo dotyczy kodu frameworka / biblioteki. Jeśli opracujesz platformę z błędem, każda aplikacja korzystająca z tej funkcji ma również ten sam błąd.
Rozwój oparty na testach zapewnia dodatkową warstwę bezpieczeństwa, jeśli chodzi o testy. Jeśli napiszesz testy obok lub nawet po kodzie, który chcesz przetestować, istnieje realne ryzyko, że pomylisz testy. Jeśli najpierw napiszesz wszystkie testy, to sposób, w jaki kod działa wewnętrznie, nie może wpłynąć na to, dla czego piszesz testy, dlatego istnieje mniejsze prawdopodobieństwo, że przypadkowo napiszesz testy, które uznają, że dane dane są błędne.
Programowanie testowe zachęca również programistów do pisania kodu, który jest łatwy do przetestowania, ponieważ nie chcą poświęcać sobie więcej pracy! Kod, który jest łatwy do przetestowania, zwykle jest kodem łatwym do zrozumienia, ponownego wykorzystania i konserwacji.
A konserwacja to miejsce, w którym naprawdę będziesz czerpać korzyści z TDD. Zdecydowana większość wysiłku programistycznego poświęconego oprogramowaniu jest związana z konserwacją. Oznacza to dokonywanie zmian w kodzie aktywnym, aby nadać mu nowe funkcje, naprawić błędy lub dostosować go do nowych sytuacji. Dokonując takich zmian, chcesz mieć pewność, że wprowadzone zmiany mają pożądany efekt, a co ważniejsze, nie powodują nieoczekiwanego efektu domina. Jeśli masz pełny pakiet testowy dla swojego kodu, łatwo jest sprawdzić, czy wszelkie wprowadzone zmiany nie psują czegoś innego, a jeśli wprowadzone zmiany powodują uszkodzenie czegoś innego, możesz szybko znaleźć przyczynę. Korzyści są długoterminowe.
W swoim pytaniu powiedziałeś:
To wydaje mi się sugerować, że nie do końca się testujesz. Test jednostkowy ma być niezwykle prosty, po prostu sekwencja wywołań metod, po których następuje stwierdzenie, aby porównać oczekiwany wynik z faktycznym wynikiem. Mają być proste, ponieważ błędy w twoich testach byłyby katastrofalne, a jeśli wprowadzisz do testu pętle, rozgałęzienia lub inne sterowanie rzutami programu, wtedy bardziej prawdopodobne jest, że w teście zostanie wprowadzony błąd. Jeśli spędzasz dużo czasu na debugowaniu testów, oznacza to, że twoje testy są zbyt skomplikowane i powinieneś je uprościć.
Jeśli testów nie można uprościć, sam ten fakt sugeruje, że coś jest nie tak z testowanym kodem. Na przykład, jeśli twoja klasa ma długie metody, metody z wieloma instrukcjami if / elseif / else lub switch lub dużą liczbą metod, które mają złożone interakcje podyktowane obecnym stanem klasy, testy z konieczności będą musiały być niezwykle złożone aby zapewnić pełne pokrycie kodu i przetestować wszystkie ewentualności. Jeśli twoja klasa ma zakodowane na stałe zależności od innych klas, to ponownie zwiększy liczbę obręczy, do których będziesz musiał przejść, aby skutecznie przetestować swój kod.
Jeśli utrzymujesz swoje klasy małe i wysoce skoncentrowane, przy użyciu krótkich metod z kilkoma ścieżkami wykonywania i próbujesz wyeliminować stan wewnętrzny, testy można uprościć. I to jest sedno sprawy. Dobry kod jest z natury łatwy do przetestowania. Jeśli kod nie jest łatwy do przetestowania, prawdopodobnie jest z nim coś nie tak.
Pisanie testów jednostkowych przynosi korzyści na dłuższą metę, a unikanie ich to po prostu gromadzenie problemów na później. Być może nie znasz pojęcia długu technicznego, ale działa on podobnie jak dług finansowy. Nie pisanie testów, nie komentowanie kodu, pisanie w zakodowanych na stałe zależnościach, a więc sposoby na zadłużenie się. „Pożyczasz” czas, wcześnie skracając rogi, co może pomóc ci dotrzymać napiętego terminu, ale oszczędzasz czas wcześniej w projekcie. Każdy dzień, który mija bez czyszczenia kodu, prawidłowe komentowanie go lub zbudowanie pakietu testowego będzie Cię kosztować. Im dłużej to trwa, tym większe jest zainteresowanie. W końcu odkryjesz, że Twój kod stał się splątanym bałaganem, do którego nie możesz wprowadzać zmian bez wywoływania niezamierzonych konsekwencji.
Możesz pomyśleć o pisaniu testów jednostkowych wcześnie i aktualizowaniu ich jako formie „kredytu technicznego”. Czas spędzasz w banku, spędzając go wcześnie w projekcie na przestrzeganie dobrych praktyk. Zyskasz zainteresowanie tym foresightem później, gdy przejdziesz do fazy konserwacji projektu. Kiedy chcesz dokonać zmiany, możesz łatwo zweryfikować poprawność zmiany i że nie ma ona żadnych niepożądanych efektów ubocznych, a także możesz szybko otrzymywać aktualizacje bez problemów. Jeśli pojawią się błędy, możesz dodać nowy test jednostkowy, który wykonuje błąd, a następnie napraw błąd w kodzie. Przy następnym uruchomieniu testu jednostkowego będziesz mógł sprawdzić, czy błąd został naprawiony i że nie spowodował żadnych innych problemów. Co więcej, unikniesz „regresji”,
TL: DR - Tak, to pomoc w prawdziwym świecie, ale to inwestycja. Korzyści stają się widoczne dopiero później.
źródło
Często używam TDD w pracy. Z mojego doświadczenia wynika, że TDD usprawiedliwia się, ponieważ nie płacisz dodatkowego czasu ani wysiłku, oszczędzasz go.
Ponieważ używam TDD, spędzam znacznie mniej czasu na debugowaniu lub tym podobnych. Po prostu działa od początku, ponieważ nie uważam kodu produkcyjnego za napisany, dopóki testy nie przejdą pomyślnie.
Kontrola jakości zgłasza znacznie mniej błędów, więc oszczędzamy koszty naprawy naszego kodu po wydaniu. Wynika to z faktu, że TDD nie pozwala pisać kodu bez testu, więc zasięg kodu jest znacznie lepszy.
Mogę uruchamiać mój (produktywny) kod znacznie częściej i szybciej, ponieważ nie muszę uruchamiać całego serwera aplikacji. Rozpoczęcie testu jednostkowego jest o rząd wielkości szybsze. Oczywiście czerpię z tego korzyści tylko wtedy, gdy test jest już wykonywalny, gdy chcę wypróbować produktywny kod. Kiedy testy następują później, ta korzyść jest tracona.
Robię znacznie mniej testów ręcznych. Moi koledzy, którzy nie ćwiczą TDD, spędzają dużo czasu na przeglądaniu aplikacji, dopóki nie osiągną punktu, w którym nowy kod jest wykonywany. Testuję ręcznie tylko raz, tuż przed zatwierdzeniem kontroli wersji.
Nawet jeśli używam debugera, debugowanie wykonania testu jest znacznie szybsze niż całej aplikacji.
Może myślisz o testach jednostkowych jako testach regresji. Jest to jeden z ich celów, ale zrozumienie ich jako narzędzia do rozwoju czyni je o wiele bardziej wartościowymi.
źródło
Kolejna zaleta (oprócz tych wymienionych przez inne osoby, które udzieliły odpowiedzi) pojawia się, gdy testerzy akceptacji klienta lub (zabraniający niebios) użytkownicy produkcyjni wykryją błąd. Zamień raport o błędzie w test w stylu TDD dla klasy, która wydaje się być winna. Zobacz, jak się nie udaje. Napraw to. Patrz, jak mija. Wtedy wiesz, że naprawiłeś błąd. Ta technika pozwoliła mi zaoszczędzić godziny.
źródło
Cóż, wiem, że osobiście korzystam z tego, że jestem dwa razy szybszy niż moi inni programiści i piszę mniej niż połowę błędów, które robią, ponieważ NIE robią TDD. Ludzie, którzy prawdopodobnie powinni być lepsi ode mnie nawet ... Przebijam ich co najmniej 2 razy.
Nie dotarłem tam od razu. Jestem całkiem dobry w pisaniu kodu z mankietu i bez uprzęży. Wydawało się, że to wielka marnotrawstwo, żeby napisać te wszystkie dodatkowe bzdury. Ale robi kilka rzeczy, w tym (nie wyłącznie):
Przykładem tego późniejszego fragmentu jest projekt, nad którym obecnie pracuję, w którym kierownik nagle postanowił CAŁKOWICIE przepisać używany protokół komunikacyjny z prawie 0 powodów. Byłem w stanie zareagować na tę zmianę w ciągu 2 godzin, ponieważ oddzieliłem ją od wszystkich innych i byłem w stanie pracować nad nią całkowicie niezależnie, aż do ostatniego powiązania i zintegrowania jej przetestowania. Większość moich współpracowników prawdopodobnie byłaby przy tym przez dzień lub dłużej, ponieważ ich kod nie byłby oddzielony i zmienialiby się tu, tam, wszędzie ... kompilując wszystko ... testowanie integracji ... powtórz, powtórz ... Trwa o wiele dłużej i nie jest tak stabilna.
źródło
Odpowiedź brzmi tak. W mojej firmie rozwijamy aplikację C ++ od ponad 20 lat. W ubiegłym roku wprowadziliśmy TDD w niektórych nowych modułach, a odsetek wad znacznie spadł. Podobało nam się tak bardzo, że niektórym z nas dodaje testy do starszego kodu za każdym razem, gdy coś tam zmieniamy.
Co więcej, cały moduł został ukończony od początku do końca, przechodząc przez produkcję, bez wykazywania błędu (i jest to również moduł krytyczny). W związku z tym jego rozwój był szybszy niż zwykle, ponieważ zwykle to, co by się wydarzyło, polegałoby na tym, że moduł byłby „skompletowany”, ale zwrócił 4-5 razy z testów beta poprawek błędów. Była to znaczna poprawa, a programiści byli bardziej zadowoleni z nowego procesu.
Nie zrobiłem dużo Rails TDD, ale zrobiłem wiele w C ++, C #, Java i Python. Mogę powiedzieć, że to na pewno działa. Domyślam się, że spędzasz dużo czasu na myśleniu o nazwach testowych, ponieważ nie jesteś wystarczająco pewny siebie. Najpierw napisz test, ale pozwól swojej kreatywności płynąć ...
Zauważyłem, że kiedy naprawdę zrozumiesz TDD, zaczniesz trochę mniej przejmować się „Jak mam nazwać ten test ... argh!”, I po prostu z nim płyniesz, refaktoryzując i dostosowując już napisane testy dopasowane do aktualnej sytuacji.
Czas na napiwek
Wskazówka nr 1
Więc wskazówka, która moim zdaniem powinna pomóc ci najbardziej, to nie martwić się tak bardzo. Jedną z najładniejszych rzeczy w TDD jest to, że daje ci odwagę zmieniania rzeczy, które już są napisane i działają. I to obejmuje testy.
Wskazówka nr 2
Rozpocznij nowe testy klasowe prostym testem „CanCreate”, aby skierować swój umysł we właściwym kierunku, tak jak w przypadku „Ok, pracuję teraz nad tą klasą… racja”.
Następnie zacznij dodawać kolejne testy, ale tylko jeden na raz, i upewnij się, że każdy test, który tworzysz, jest kolejnym najprostszym przypadkiem, który przychodzi ci na myśl w tym momencie (pomyśl o tym przez nie więcej niż 30 sekund, a potem limit czasu z najlepszym, co masz w tym momencie).
I pamiętaj
Nie przejmuj się refaktoryzacją istniejących testów, a nawet usunięciem przestarzałych lub zbędnych. Niewiele osób zdaje sobie z tego sprawę, ale w TDD faktycznie dostajesz 2 siatki bezpieczeństwa w cenie 1. Twoje testy są siatką bezpieczeństwa dla zmian kodu produkcji, ale twój kod produkcji jest również siatką bezpieczeństwa dla refaktoryzacji testów. Związek jest wzajemny. To właściwie dobry przypadek ciasnego połączenia.
Daj to jeszcze raz. I polecam oglądać Clean Cast Casts , szczególnie te o TDD.
źródło
Nietrywialny przykład w świecie rzeczywistym:
Musiałem napisać funkcję transformacji struktury danych. Dane wejściowe byłyby strukturą danych (właściwie zagnieżdżoną strukturą danych, podobnie jak drzewo), a dane wyjściowe byłyby podobną strukturą danych. Nie mogłem sobie wyobrazić rzeczywistej transformacji w moim umyśle. Jedną z głównych zalet TDD (w każdym razie dla mnie) jest egzekwowanie kroków dziecka, jeśli nie wiesz, jak postępować (patrz Kent Becks „TDD przez przykład”). Ponieważ nie wiedziałem, dokąd to zmierza, zacząłem od prostych przypadków podstawowych, takich jak puste lub trywialne dane wejściowe, i pracowałem aż do bardziej skomplikowanych przypadków, aż doszedłem do wniosku, że wszystkie je omówiłem. W końcu miałem działający algorytm i testy, które to udowodniły. Testy nie tylko dowodzą, że moja implementacja działa teraz, ale także powstrzymują mnie od popierania czegokolwiek później.
źródło
Nie podoba mi się pomysł ślepego podążania za ogólnymi radami, ponieważ nie wierzę, że istnieje jedna uniwersalna sugestia, która pomoże większości programistów zwiększyć produktywność i zmniejszyć wady aplikacji. Z mojego doświadczenia wynika, że im bardziej martwisz się o jakość, tym więcej stracisz w ilości dostarczanych nowych funkcji. Zatem poziom znaczenia, jaki chcesz nadać jakości w stosunku do możliwości dostawy, będzie w rzeczywistości zależeć od twojego produktu i aktualnej strategii i najprawdopodobniej będzie to ktoś inny, kto zdecyduje strategicznie, co jest na razie najważniejsze: solidność lub dostarczalność.
Nawet ta decyzja nie jest czarna ani biała. Najprawdopodobniej niektóre części aplikacji muszą być niezawodne, podczas gdy inne nie muszą. Po określeniu, które części powinny mieć wysoki poziom jakości, należy skupić się na nich z perspektywy testowania, ponieważ chcesz zapewnić wysoką jakość tych części.
Wszystko, co powiedziałem do tej pory, nie ma nic wspólnego z TDD, szczególnie w sensie pisania testów przed wdrożeniem, ale uważam, że ważne jest, aby oddzielić korzyści płynące z przetestowania kodu od pisania testów jako pierwszych.
Gdy zrozumiesz zalety samego testowania, TDD lub nie, możesz następnie omówić strategię testowania dla kodu, który chcesz objąć testami. Niektórzy twierdzą, że jeśli napiszesz testy później, w testach spóźnisz się z pewnymi warunkami, ale uważam, że to ty powinnaś ocenić, czy dotyczy to ciebie. To na pewno mnie nie dotyczy.
Oto, jak to działa dla mnie. Zasadniczo istnieją dwie sytuacje, które zmuszają mnie do pisania testów: poprawi to tylko jakość lub przyspieszy mój rozwój niektórych funkcji. Tak więc sytuacja, w której napiszę testy, polega na tym, że w zaległościach nie ma żadnych nowych funkcji, a następnie mogę zdecydować o poprawie wydajności aplikacji, uproszczeniu bazy kodu lub ulepszeniu zestawu testów. Inną sytuacją jest potrzeba posiadania solidnego działającego kodu, w którym błędy miałyby wystarczająco duży wpływ na prawdziwych klientów. Jeszcze inny służy do testowania złożonego kodu, który można łatwo złamać podczas pracy nad nim. Na przykład w mojej bazie kodu znajduje się klasa QueryBuilder, która zajmuje się wieloma przypadkami użycia i łatwo byłoby je zepsuć podczas naprawy błędu lub dodawania nowej funkcji.
Wreszcie, jest przypadek, w którym najpierw napisanie testów pozwala mi napisać funkcję szybciej niż wcale nie pisać testów. Ten QueryBuilder był również przypadkiem, w którym ta reguła miała zastosowanie, ale to nie znaczy, że TDD będzie również najlepszą ścieżką. Innym przykładem TDD pomagającym w szybkości programowania jest na przykład testowanie generowania programu Excel, podczas gdy w rzeczywistej aplikacji może być konieczne wykonanie kilku kroków za każdym razem, gdy chcesz przetestować określony warunek w generowaniu. Lub jeśli musisz utworzyć jakieś rekordy w celu przetestowania funkcji, a ich ręczne usunięcie po ręcznym przetestowaniu kodu jest trudne lub niemożliwe.
Jeśli więc łatwiej jest ci odtworzyć kroki, aby uruchomić programowo kod (w trakcie testów), skorzystaj z niego. Ale jeśli napisanie testu jest bardziej skomplikowane niż przetestowanie go ręcznie, musisz zdecydować, czy nadszedł czas, aby skupić się na jakości, czy masz dużo zapytań w zaległościach, a ktoś w firmie prawdopodobnie będzie wiedział o tym lepiej i pozwoli ci wiedzieć, gdzie powinieneś się skupić zgodnie z ich bieżącymi potrzebami i strategią firmy.
W idealnym świecie cały kod jest testowany, ale nie można udawać, że nie ma kompromisu i założyć, że TDD jest zawsze najlepszą i jedyną drogą. Podobnie jak w przypadku wszystkich najlepszych praktyk, zawsze musisz skupić się na tym, co jest najlepsze dla firmy, w której pracujesz, zamiast na tym, co jest lepsze dla Ciebie. Po rozpoczęciu działalności na własny rachunek możesz decydować się na wykonywanie TDD przez cały czas, jeśli uważasz, że jest to najlepsza ścieżka. Jeśli Twoja firma uważa, że cały kod powinien zostać przetestowany, musisz napisać testy dla całego napisanego kodu. Ale w większości przypadków musisz uzyskać pełny obraz i zrozumieć kompromisy, zanim podejmiesz jakąkolwiek decyzję. Przykro nam, ale nie jest to nauka ścisła i nie ma łatwej (ani trudnej), uniwersalnej odpowiedzi, której należy przestrzegać za każdym razem.
Tak samo jak w przypadku wzorów. Dowiedz się, jak działają i dlaczego zostały stworzone, jakie problemy rozwiązują i jakie są ich wady. Zrozumienie rozumowania jest o wiele ważniejsze niż zapamiętywanie proponowanych rozwiązań. To, co dziś jest kosztowną operacją, można łatwo osiągnąć jutro za pomocą innych technologii. Jeśli przesłanka dla jakiegoś dobrze ustalonego rozwiązania nie jest już ważna, najprawdopodobniej rozwiązanie nie jest już najlepszym rozwiązaniem. Gdy zmieniają się wymagania, dostępna technologia lub strategia firmy, zawsze powinieneś ponownie oszacować swój zestaw narzędzi, a kiedy tak się stanie, musisz zrozumieć, dlaczego wybrałeś każdą ścieżkę w pierwszej kolejności, zamiast brać je za najlepsze.
źródło