Czy rozwój oparty na testach (TDD) rzeczywiście przyniósł korzyści projektowi z prawdziwego świata?


36

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?


1
Zaoszczędziło mi to jeszcze kilka razy: ponieważ jesteśmy wieloma ludźmi przy tym samym projekcie, ponieważ aktualizacje klejnotów mogą mieć nieznane skutki uboczne, ponieważ jeśli wszystko jest zielone i mam błąd, wiem, gdzie nie warto znaleźć jego katalogu głównego.
apneadiving


3
butunclebob.com/ArticleS.UncleBob.JustTenMinutesWithoutAtest Oto historia od wuja Boba o sytuacji w prawdziwym świecie.
Hakan Deryal

1
Na początku myślałem, że testy świetnie sprawdzą się, gdzie nie ma błędów, ale szybko się nauczyłem, jak zauważył @Hakan w artykule wuja Boba, na ogół pojawia się, ponieważ przegapiłeś przypadek testowy. Co czyni te testy całkiem bezużytecznymi. W rzeczywistości w tym artykule podkreślono, że rozwój przyrostowy jest tym, co działa.
James

1
„Uważam, że spędzam znacznie więcej czasu na debugowaniu moich testów, aby powiedzieć im, co naprawdę mam na myśli, niż debugowanie faktycznego kodu” : ale czy nie jest to dokładnie korzyść? Czy nadal wydaje ci się, że spędzasz dużo czasu debugując „rzeczywisty kod”? Zwolennicy TDD twierdzą, że czas poświęcony na znalezienie sposobu na przetestowanie kodu jest tak naprawdę wysiłkiem projektowym , który przyniesie korzyści Twojemu kodowi.
Andres F.

Odpowiedzi:


26

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 .

AbstrakcyjnyProgramowanie oparte na testach (TDD) to praktyka opracowywania oprogramowania, która jest stosowana od dziesięcioleci sporadycznie. W tej praktyce inżynier oprogramowania przechodzi cykl minut po minucie między pisaniem nieudanych testów jednostkowych a pisaniem kodu implementacyjnego, aby przejść te testy. Rozwój Testdriven niedawno stał się krytyczną praktyką umożliwiającą stosowanie zwinnych metodologii tworzenia oprogramowania. Jednak niewiele dowodów empirycznych potwierdza lub obala użyteczność tej praktyki w kontekście przemysłowym. Studia przypadków przeprowadzono z trzema zespołami programistycznymi w firmie Microsoft i jednym w IBM, które przyjęły TDD. Wyniki studiów przypadków wskazują, że gęstość defektów przed wydaniem czterech produktów spadła od 40% do 90% w porównaniu do podobnych projektów, które nie stosowały praktyki TDD. Subiektywnie,

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).


2
Czy podczas dyskusji na temat Meta.StackOverflow możesz dodać dodatkowe informacje z gazety, które mogą być istotne dla pytającego , a także dla przyszłych osób, które znajdą to pytanie?
Thomas Owens

2
@ThomasOwens, pomyślałem, że wniosek („TDD dodaje 15–35% czasu rozwoju w zamian za 40–90% zmniejszenie gęstości defektów”) był dodatkową informacją, która odpowiada na pierwotne pytanie <_ <

4
Ten post został oznaczony jako niewystarczający. Nie przeczytałem jeszcze tego artykułu, ale wygląda na to, że ludzie chcą więcej informacji dodanych do treści odpowiedzi. Może dyskutujesz więcej o konkretnych warunkach zastosowanych w badaniu?
Thomas Owens

99% wszystkich statystyk jest fikcyjnych. : P Ale tak naprawdę chodzi o kontekst. W jakim zespole? Duża liczba miernych deweloperów Java? Tak, wierzę, że TDD pomógłby im w wydajności. Ale to nie znaczy, że posiadanie umiejętności architektonicznych do projektowania i doceniania solidnego kodu nie pomogłoby im jeszcze bardziej, a IMO, pierwsze TDD w testach, mogłoby bardzo łatwo uniemożliwić im nauczenie się, jak to robić poprawnie. I tak, słyszałem, że to pomaga w projektowaniu. W pewnym stopniu jest to prawdopodobnie prawda, ale nadal nie jest to potwierdzone, a zespół pomaga w rozwiązaniu problemu root IMO.
Erik Reppen

byłoby miło, gdyby pojawiło się więcej artykułów z Cyfrowej Biblioteki ACM lub dodano słowa kluczowe do wykorzystania w wyszukiwarce. potrzebujemy więcej rygorystyczności w naszych odpowiedziach, gdy mówimy o zwinności i TDD
Rudolf Olah,

16

Widzę pewne korzyści z pisania testów dla niektórych rzeczy, ale bardzo niewiele. I chociaż podoba mi się pomysł, aby najpierw napisać test, okazuje się, że spędzam znacznie więcej czasu na debugowaniu moich testów, aby powiedzieć im, co naprawdę mam na myśli, niż debugowanie faktycznego kodu.

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.

Ale jak dobrze działa na prawdziwych projektach?

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.


9

Ogromnie skorzystaliśmy.

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


3
„W końcu wrócimy i rozwiążemy te problemy”. - prawdopodobnie nie ... nie, chyba że suka cię spoliczkuje jakimś przerażającym robakiem. Obszary te staną się podstawą wszystkiego, co poprowadzi cały projekt do przodu, ponieważ nikt nie będzie chciał inwestować zasobów, aby je przerobić i nikt nie będzie chciał wymuszać żadnych zmian, które mogłyby zrobić coś złego. Zdarza się za każdym razem: P
Edward Strange

Zgadujesz, kiedy mówię ci, co dzieje się w firmie. Kiedy zatwierdzamy, możemy zatwierdzić kod z 70% pokryciem kodu. Jest to stale zwiększane przez ołów CI. W ciągu miesięcy minimalny próg pokrycia kodu zostanie zwiększony o niewielki procent. Po tym nie będzie już innego wyboru, jak wprowadzić więcej testów.
CodeART

7

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.


2
Wydaje mi się, że to pytanie dotyczy przede wszystkim testu, a później implementacji stratergy. Testy są oczywiście przydatne do debugowania aplikacji, w których samodzielne testowanie każdej możliwości byłoby uciążliwe.
Alex Hope O'Connor

6

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.


8
Ta odpowiedź wydaje się być całkowicie poza pytaniem, ponieważ pytanie wymaga przykładów z prawdziwego świata . Ale ponieważ trzy osoby uważały, że „ta odpowiedź jest przydatna”, muszę coś przeoczyć.

3
Zgadzam się, ale nie mam reputacji, by głosować za. To jest po prostu „TDD daje lepsze wyniki” bez żadnego przykładu projektu opartego na TDD w zakresie konserwacji, aby poprzeć odpowiedź, której chciałem uniknąć.
James

Teraz, gdy kilka osób się ze mną zgodziło, odważę się przegłosować. Czy jakikolwiek autor lub autor, zgłoś się i powiedz nam, dlaczego to dobra odpowiedź?

@delnan „I dare downvote” - ciekawy wybór słów. Czy edycja przypadła Ci do gustu?

Tak, usunąłem moją recenzję, gdy ją zauważyłem.

5

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ś:

Widzę pewne korzyści z pisania testów dla niektórych rzeczy, ale bardzo niewiele. I chociaż podoba mi się pomysł, aby najpierw napisać test, okazuje się, że spędzam znacznie więcej czasu na debugowaniu moich testów, aby powiedzieć im, 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).

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.


1
Kupiłem tę logikę kilka miesięcy temu. Podoba mi się pomysł TDD, po prostu uważam, że jest to trochę niepokojące. Zauważam również, że nawet tutaj nie ma faktycznych przykładów, w których opłacenie dziedziczenia projektu opartego na TDD się opłaciło. Czy rzeczywiście wróciłeś do starej bazy kodu, która zawierała wiele testów jednostkowych i się opłaciła?
James

Niestety nie, ponieważ nikt inny nie wydaje się budować testów jednostkowych, przynajmniej nie na żadnym kodzie odziedziczonym po poprzednich programistach. Gdyby tak było, moje życie byłoby o wiele łatwiejsze. Proponuję zajrzeć do książki w linku, która zawiera przykłady ze świata rzeczywistego, chociaż jest przeznaczona raczej dla PHP niż Railsów. amazon.com/…
GordonM

Jestem wielkim krytykiem powszechnego użytku, ale nie winiłbym nikogo za stosowanie tego podejścia w osadzonym lub krytycznym systemie finansowym.
Erik Reppen

4

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.


Jakość jest darmowa!
MathAttack

2
Zła jakość jest droga!
Wolfgang

3

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.


2

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):

  • Wymuszanie projektu ukierunkowanego na oddzielenie i ponowne użycie (wszystko musi zostać ponownie użyte w teście jednostkowym).
  • Dostarczenie platformy do programowania kodu w małych porcjach i modułach, dzięki czemu nie muszę wszystko rozgryzać i kończyć przed uruchomieniem prostego testu typu „Czy to nawet kompiluje i przyjmuje dane wejściowe”.
  • Zapewniając szybką platformę testową do wprowadzania zmian, gdy ludzie żądają zmian funkcji, których się nie spodziewałem.

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.


2

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.


1

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.


-1

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.


to nawet nie próbuje odpowiedzieć na zadane pytanie: „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 z TDD i ma pełny zestaw testów jednostkowych i faktycznie poczułeś wypłatę? ”
komar

1
Odpowiada, ale ponieważ nie podzielasz mojej opinii, dajesz -1 do niego :) Zasadniczo każdy, kto nie będzie próbował pokazać wartości TDD, udzieli niechcianej odpowiedzi z twojego punktu widzenia;) Niech zgadnę . Jesteś ewangelizatorem TDD, prawda? :) Nawiasem mówiąc, prawdziwym pytaniem autora jest to, czy TDD się opłaca, czy nie. Nie musisz ćwiczyć TDD, aby na to odpowiedzieć. Czy Fortran opłaca się pisać aplikacje internetowe? Próbowałeś, zanim odpowiedziałeś?
rosenfeld

Nie mam zdania na temat TDD i nie używam głosów tak jak / nie lubię (to strona z pytaniami i odpowiedziami, a nie Facebook). Według mojej lektury ta „odpowiedź” po prostu nie odnosi się do zadanego pytania, ani pozytywnie, ani negatywnie
komnata

Z mojego punktu widzenia nie jest to pytanie techniczne, na przykład „jak zrobić X z nginx?”. Odpowiedzi na takie pytania są poprawne, ale nie na pytania jakościowe i subiektywne, gdy autor naprawdę chce poznać opinie innych na temat TDD i czy warto. To była moja próba pokazania mojego punktu widzenia. Nie mam pojęcia, jak odpowiedź może być właściwa, ponieważ wszystkie wydają mi się osobistymi opiniami. Nie można skutecznie zmierzyć, czy wartość TDD jest warta, czy nie. Wszelkie artykuły próbujące to zrobić są zasadniczo błędne.
rosenfeld

„Na tej stronie znajdziesz odpowiedzi na wszystkie trasy . To nie jest forum dyskusyjne ...”
gnat
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.