Rozwój oparty na testach (TDD) jest obecnie duży. Często widzę, że jest to zalecane rozwiązanie dla szerokiej gamy problemów tutaj w Programmers SE i innych miejscach. Zastanawiam się, dlaczego to działa.
Z technicznego punktu widzenia zastanawia mnie to z dwóch powodów:
- Podejście „test pisemny + refaktor do zaliczenia” wygląda niesamowicie antyinżynieryjnie. Gdyby inżynierowie budowlani zastosowali to podejście do budowy mostów lub projektanci samochodów dla swoich samochodów, przekształciliby swoje mosty lub samochody po bardzo wysokich kosztach, a rezultatem byłby załatany bałagan bez dobrze przemyślanej architektury . Wytyczne „refaktoryzacji do przejścia” są często traktowane jako mandat do zapomnienia o projekcie architektonicznym i zrobienia wszystkiego , co jest konieczne do wykonania testu; innymi słowy, test, a nie użytkownik, określa wymaganie. W tej sytuacji, w jaki sposób możemy zagwarantować dobre „podobieństwa” w wynikach, tj. Wynik końcowy, który jest nie tylko poprawny, ale także rozszerzalny, solidny, łatwy w użyciu, niezawodny, bezpieczny, bezpieczny itp.? Tak zwykle robi architektura.
- Testowanie nie gwarantuje, że system działa; może tylko pokazać, że nie. Innymi słowy, testowanie może pokazać, że system zawiera defekty, jeśli test nie powiedzie się, ale system, który przejdzie wszystkie testy, nie jest bezpieczniejszy niż system, który je zaliczy. Kluczowe znaczenie ma tutaj zasięg testu, jakość testu i inne czynniki. Fałszywie bezpieczne odczucia, które wielu osobom wywołuje „zielone” wyniki, zostały zgłoszone w przemyśle cywilnym i lotniczym jako wyjątkowo niebezpieczne, ponieważ można je interpretować jako „system jest w porządku”, gdy tak naprawdę oznacza „system jest tak dobry” jako nasza strategia testowania ”. Często strategia testowania nie jest sprawdzana. Lub kto testuje testy?
Podsumowując, bardziej martwię się bitem „napędzanym” w TDD niż bitem „testowym”. Testowanie jest całkowicie OK; to, czego nie dostaję, to kierowanie projektem przez robienie tego.
Chciałbym zobaczyć odpowiedzi zawierające powody, dla których TDD w inżynierii oprogramowania jest dobrą praktyką i dlaczego problemy, które wyjaśniłem powyżej, nie są istotne (lub nie są odpowiednie) w przypadku oprogramowania. Dziękuję Ci.
Odpowiedzi:
Myślę, że tutaj jest jedno nieporozumienie. W projektowaniu oprogramowania projekt jest bardzo zbliżony do produktu. W inżynierii lądowej, architekturze projekt jest oddzielony od rzeczywistego produktu: istnieją plany, które zawierają projekt, które następnie są materializowane w gotowym produkcie, i są one rozdzielane przez ogromną ilość czasu i wysiłku.
TDD testuje projekt. Ale każdy projekt samochodu i projekt budynku jest również testowany. Najpierw obliczane są techniki konstrukcyjne, następnie testowane w mniejszej skali, a następnie testowane w większej skali, a następnie wypuszczane w prawdziwym budynku. Kiedy wynaleźli na przykład belki H i ładunek, zapewnijcie, że zostało to wypróbowane i wypróbowane ponownie, zanim zbudują pierwszy most.
Projekty samochodów są również testowane, projektując prototypy i tak, oczywiście, dostosowując rzeczy, które nie są dokładnie właściwe, dopóki nie spełnią oczekiwań. Część tego procesu jest jednak wolniejsza, ponieważ, jak powiedziałeś, z produktem nie można wiele zepsuć. Ale każda przeprojektowanie samochodu opiera się na doświadczeniach zdobytych podczas poprzednich, a każdy budynek ma za sobą około trzydziestu lat fundamentów dotyczących znaczenia przestrzeni, światła, izolacji, wytrzymałości itp. Szczegóły są zmieniane i ulepszane, zarówno w budynkach oraz w przeprojektowaniu dla nowszych.
Ponadto części są testowane. Być może nie w tym samym stylu co oprogramowanie, ale części mechaniczne (koła, zapalniki, kable) są zwykle mierzone i poddawane naprężeniom, aby wiedzieć, że rozmiary są prawidłowe, nie ma żadnych nieprawidłowości itp. Mogą być prześwietlone lub laserowo zmierzone, stukają cegły, aby wykryć zepsute, mogą być faktycznie przetestowane w jakiejś konfiguracji lub innej, lub narysują ograniczoną reprezentację dużej grupy, aby naprawdę przetestować.
To wszystko, co możesz wprowadzić w TDD.
I rzeczywiście, testowanie nie jest gwarancją. Programy ulegają awarii, samochody się psują, a budynki zaczynają robić śmieszne rzeczy, gdy wieje wiatr. Ale ... „bezpieczeństwo” nie jest pytaniem logicznym. Nawet jeśli nie możesz nigdy uwzględnić wszystkiego, możliwość pokrycia - powiedzmy - 99% ewentualności jest lepsza niż pokrycie tylko 50%. Niezbadanie, a następnie ustalenie, czy stal nie osiadła dobrze, jest krucha i pęka przy pierwszym uderzeniu młota, gdy tylko postawisz swoją główną konstrukcję, to zwykła strata pieniędzy. To, że istnieją jeszcze inne obawy, które mogą nadal zranić budynek, nie czyni go głupszym, pozwalając na łatwą do uniknięcia wadę sprowadzającą projekt.
Jeśli chodzi o praktykę TDD, jest to kwestia równoważenia. Koszt zrobienia tego w jedną stronę (na przykład nie testowanie, a następnie podniesienie elementów później), w porównaniu z kosztem zrobienia tego w inny sposób. To zawsze jest równowaga. Ale nie sądzę, że inne procesy projektowania nie mają testów i TDD.
źródło
IMO, większość historii sukcesu TDD jest fałszywa i służy wyłącznie celom marketingowym. Może być bardzo mało sukcesów, ale tylko w przypadku małych aplikacji. Pracuję nad dużą aplikacją Silverlight, w której stosowane są zasady TDD. Aplikacja przeszła setki testów, ale wciąż nie jest stabilna. Niektórych części aplikacji nie można przetestować z powodu złożonych interakcji użytkownika. Wynikowe testy z dużą ilością próbnych i trudnych do zrozumienia kodów.
Początkowo, kiedy próbowaliśmy TDD, wszystko wydaje się dobre. Byłem w stanie napisać wiele testów i wykpić części, które są trudne do testów jednostkowych. Gdy masz już dość kodu i wymagana jest zmiana interfejsu, jesteś wkręcony. Wiele testów wymaga naprawy, a ty przepiszesz więcej testów niż rzeczywista zmiana w kodzie.
Peter Norvig wyjaśnia swój pogląd na TDD w książce Coders At Work.
źródło
well, you haven't done TDD right!
Test Driven Design działa dla mnie z następujących powodów:
Jest to wykonalna forma specyfikacji.
Oznacza to, że z przypadków testowych można zobaczyć:
Najpierw piszesz widok z zewnątrz.
Często kod jest pisany w taki sposób, że najpierw rozwiązujesz problem, a następnie zastanawiasz się, jak ma być wywołany właśnie napisany kod. Daje to często niezręczny interfejs, ponieważ często łatwiej jest „po prostu dodać flagę” itp. Myśląc „musimy to zrobić, aby skrzynki testowe wyglądały tak”, odwracasz to. Zapewni to lepszą modułowość, ponieważ kod zostanie napisany zgodnie z interfejsem wywołującym, a nie na odwrót.
Zwykle powoduje to również czystszy kod, który wymaga mniej objaśniającej dokumentacji.
Zrobisz szybciej
Ponieważ masz specyfikację w postaci możliwej do uruchomienia, robisz to po przejściu pełnego zestawu testów. Możesz dodać więcej testów, wyjaśniając rzeczy na bardziej szczegółowym poziomie, ale jako podstawową zasadę masz bardzo wyraźny i widoczny wskaźnik postępu i kiedy skończysz.
Oznacza to, że możesz stwierdzić, kiedy praca jest konieczna, czy nie (czy to pomaga zdać test), że w końcu musisz zrobić mniej.
Dla tych, którzy zastanawiają się nad tym, mogą być dla nich przydatne, zachęcam do korzystania z TDD do następnej procedury bibliotecznej. Powoli skonfiguruj uruchamialną specyfikację i spraw, aby kod przeszedł testy. Po zakończeniu specyfikacja uruchamialna jest dostępna dla wszystkich, którzy muszą zobaczyć, jak wywołać bibliotekę.
Ostatnie badania
„Wyniki badań przypadków wskazują, że gęstość defektów przed wydaniem czterech produktów spadła od 40% do 90% w porównaniu z podobnymi projektami, które nie stosowały praktyki TDD. Subiektywnie, zespoły odnotowały wzrost o 15 do 35% początkowy czas opracowywania po przyjęciu TDD. ” ~ Wyniki i doświadczenia 4 zespołów przemysłowych
źródło
Proces tworzenia oprogramowania nie jest procesem pisania kodu. Żaden projekt oprogramowania nie powinien zaczynać się od planu „szerokiego zakresu”. Podobnie jak projekt pomostowania dwóch brzegów rzeki najpierw taki plan jest potrzebny.
Podejście TDD odnosi się (głównie) do testów jednostkowych - przynajmniej tak ludzie myślą o tym - czyli tworzenia bitów kodu na najniższym poziomie. Kiedy wszystkie cechy i zachowania są już zdefiniowane i wiemy, co chcemy osiągnąć.
W inżynierii budowlanej wygląda to trochę tak:
Do testowania, czy oprogramowanie działa jako całość, projektujemy inne rodzaje testów, takie jak testy użyteczności, testy integracji i testy akceptacyjne. Te również powinny zostać zdefiniowane przed rozpoczęciem faktycznej pracy nad pisaniem kodu i są wykonywane po tym, jak testy jednostkowe są zielone.
Zobacz model V: http://en.wikipedia.org/wiki/V-Model_%28software_development%29
Zobaczmy, jak to będzie działać dla mostu:
Samorząd lokalny mówi do firmy budującej mosty: „Potrzebujemy mostu, aby połączyć te dwa punkty. Most musi być w stanie pozwolić na n ruchu na godzinę i być gotowy do 21 grudnia 2012 r.” - to definicja test akceptacyjny Firma nie otrzyma pełnej kwoty (lub jakichkolwiek) pieniędzy, jeśli nie zda tego testu.
Zarządzanie firmą decyduje o harmonogramie projektu. Zakładają zespoły robocze i cele dla każdego zespołu. Jeśli drużyny nie osiągną tych celów - most nie zostanie zbudowany na czas. Jednak - tutaj jest pewien poziom elastyczności. Jeśli jeden z zespołów ma jakieś problemy, firma może to zrekompensować, zmieniając wymagania, zmieniając podwykonawców, zatrudniając więcej osób itp., Tak aby cały projekt nadal spełniał cel określony w punkcie 1.
W zespole odpowiedzialnym za projektowanie poszczególnych elementów mostu wygląda to tak, jak w przykładzie, który podałem powyżej. Czasami rozwiązanie jest oczywiste, ponieważ mamy duży zasób wiedzy na temat budowania mostów (to tak, jak przy użyciu dobrze przetestowanej biblioteki przy tworzeniu oprogramowania - zakładasz tylko, że działa zgodnie z reklamą). Czasami musisz stworzyć kilka projektów i przetestować je, aby wybrać najlepszy. Mimo to kryteria, na podstawie których badany jest składnik, są znane wcześniej.
źródło
Moim zdaniem TDD działa, ponieważ
W szczególności na zdobywane punkty
źródło
TL; DR
Programowanie jest nadal działaniem projektowym, a nie konstrukcyjnym. Pisanie testów jednostkowych po fakcie potwierdza tylko, że kod robi to, co robi, a nie, że robi coś pożytecznego. Niepowodzenia testów są prawdziwą wartością, ponieważ pozwalają wcześnie wykryć błędy.
Kod to projekt
W rozdziale 7 PPP „Wujek Bob” mówi bezpośrednio o tym problemie. Na samym początku rozdziału odwołuje się do doskonałego artykułu Jacka Reevesa, w którym sugeruje, że kod jest projektem (link prowadzi do strony zawierającej wszystkie trzy jego artykuły na ten temat).
Interesujące w tym argumencie jest to, że zwraca uwagę, w przeciwieństwie do innych dyscyplin inżynieryjnych, w których budowa jest bardzo kosztowną działalnością, budowa oprogramowania jest stosunkowo darmowa (skompiluj kompilację w swoim IDE, a masz już utworzone oprogramowanie). Jeśli widzisz pisanie kodu jako działanie projektowe zamiast działania konstrukcyjnego, wówczas cykl refaktora czerwono-zielonego jest w zasadzie ćwiczeniem w projektowaniu. Twój projekt ewoluuje wraz z pisaniem testów, kodem do ich spełnienia oraz refaktorem w celu zintegrowania nowego kodu z istniejącym systemem.
TDD jako specyfikacja
Testy jednostkowe, które piszesz dla TDD, są bezpośrednim tłumaczeniem specyfikacji w miarę ich rozumienia. Pisząc kod, który w minimalnym stopniu spełnia specyfikację (sprawia, że testy zmieniają kolor na zielony), cały napisany kod jest przeznaczony do określonego celu. To, czy cel ten został osiągnięty, jest potwierdzane przez powtarzalny test.
Napisz testy do funkcjonalności
Powszechny błąd w testowaniu jednostkowym zdarza się, gdy piszesz testy po kodzie, testujesz w końcu, czy kod robi to, co robi. Innymi słowy, zobaczysz takie testy
Chociaż wydaje mi się, że ten kod może być przydatny (upewnij się, że ktoś nie zrobił czegoś nieprzyzwoitego za pomocą prostej właściwości). Nie służy do sprawdzania poprawności specyfikacji. I jak powiedziałeś, pisanie tego rodzaju testów zabiera cię tylko do tej pory.
Podczas gdy kolor zielony jest dobry, wartość leży na czerwono , miałem pierwszą prawdziwą chwilę „aha” w TDD, kiedy nieoczekiwany błąd testu. Miałem zestaw testów, które miałem dla budowanego frameworka. Dodając nową funkcję, napisałem dla niej test. Następnie napisał kod, aby test przeszedł pomyślnie. Skompiluj, przetestuj ... dostał zielony na nowy test. Ale dostałem też czerwony na innym teście, którego nie spodziewałem się na czerwono.
Patrząc na niepowodzenie, odetchnęłam z ulgą, ponieważ wątpię, czy złapałbym tego robaka od dłuższego czasu, gdybym nie przeprowadził tego testu. I to był BARDZO paskudny błąd. Na szczęście miałem test, który powiedział mi dokładnie, co muszę zrobić, aby naprawić błąd. Bez testu nadal budowałbym swój system (z błędem infekującym inne moduły zależne od tego kodu), a zanim błąd został wykryty, głównym zadaniem byłoby jego poprawne naprawienie.
Prawdziwą zaletą TDD jest to, że pozwala nam wprowadzać zmiany przy lekkomyślnym porzucaniu. To jest jak siatka bezpieczeństwa do programowania. Pomyśl, co by się stało, gdyby artysta trapezowy popełnił błąd i upadł. Z siecią to żenujący błąd. Bez niej to tragedia. Z tego samego powodu TDD ratuje cię od przekształcania błędów z kością w katastrofy polegające na zabijaniu projektów.
źródło
Nie znajdziesz nikogo, kto opowiada się za Test Driven Development, a nawet Test Driven Design (są różne), co oznacza, że testy sprawdzają aplikacje. Więc nazwijmy to słomianym człowiekiem i skończmy.
Nie znajdziesz nikogo, kto by nie lubił TDD i nie jest pod wrażeniem, że testy są stratą czasu i wysiłku. Chociaż testy nie dowodzą zastosowania, są bardzo pomocne w znajdowaniu błędów.
Biorąc pod uwagę te dwie rzeczy, żadna ze stron nie robi nic innego w odniesieniu do faktycznego przeprowadzania testów oprogramowania. Obaj robią testy. Oba polegają na testowaniu, aby znaleźć jak najwięcej błędów, i oba wykorzystują testy do sprawdzenia, czy program działa tak dobrze, jak można go w tym czasie wykryć. Nikt z połową wskazówki nie sprzedaje oprogramowania bez testowania i nikt z połową wskazówki nie spodziewa się, że dzięki testowi kod, który sprzedają, będzie całkowicie bezbłędny.
Różnica między TDD a nie TDD nie polega na tym, że testy są przeprowadzane. Różnica polega na tym, kiedy testy są pisane. Testy TDD są zapisywane PRZED oprogramowaniem. W testach innych niż TDD są pisane po oprogramowaniu lub zgodnie z nim.
Problem, który widziałem w odniesieniu do tego drugiego, polega na tym, że testowanie ma tendencję do tego, że oprogramowanie jest pisane bardziej niż pożądany wynik lub specyfikacja. Nawet gdy zespół testujący jest niezależny od zespołu programistów, zespół testowy ma tendencję do patrzenia na oprogramowanie, zabawy z nim i pisania testów, które są do niego ukierunkowane.
Jedną z rzeczy, która jest zauważana przez tych, którzy badają sukces projektu, jest to, jak często klient określa to, czego chce, ludzie pracujący nad rozwojem uciekają i coś piszą, a kiedy wracają do klienta, mówiąc: „zrobione” okazuje się, że jest to całkowicie i wcale NIE to, o co prosił klient. „Ale przeszedł wszystkie testy ...”
Celem TDD jest przełamanie tego „okrągłego argumentu” i zapewnienie podstaw do testów testujących oprogramowanie, które nie jest samym oprogramowaniem. Testy są napisane w celu ukierunkowania zachowania, którego chce „klient”. Oprogramowanie jest następnie zapisywane, aby przejść te testy.
TDD jest jednak częścią rozwiązania mającego rozwiązać ten problem. To nie jedyny krok, który zrobisz. Inne rzeczy, które musisz zrobić, to upewnić się, że jest więcej opinii klientów i częściej.
Z mojego doświadczenia wynika jednak, że wdrożenie TDD jest bardzo trudne. Trudno jest napisać testy, zanim pojawi się produkt, ponieważ wiele testów automatycznych wymaga posiadania czegoś do zabawy, aby oprogramowanie do automatyzacji działało poprawnie. Trudno też znaleźć programistów, którzy nie są przyzwyczajeni do testów jednostkowych. Raz po raz mówiłem ludziom w moim zespole, żeby najpierw napisali testy. Tak naprawdę nigdy nie udało mi się tego zrobić. Ostatecznie ograniczenia czasowe i polityka zniszczyły wszelkie wysiłki, abyśmy nawet nie przeprowadzali testów jednostkowych. To oczywiście prowadzi nieuchronnie do przypadkowego i poważnego sprzężenia projektu, dlatego nawet gdybyśmy tego chcieli, jego wdrożenie byłoby zbyt kosztowne. Unikanie tego jest tym, co TDD ostatecznie zapewnia programistom.
źródło
Najpierw zaprojektuj
TDD nie jest usprawiedliwieniem do pominięcia projektu. Widziałem wielu wskakujących do „zwinnego” modemu, ponieważ myśleli, że mogą od razu zacząć kodować. Dzięki True Agile będziesz w stanie kodować statystyki znacznie szybciej niż dobre praktyki inżynieryjne (inne dziedziny), które zainspirowały proces wodospadu.
Ale przetestuj wcześnie
Kiedy ktoś mówi, że test napędza projekt, oznacza to po prostu, że można zastosować testy na bardzo wczesnym etapie fazy projektowania, na długo przed jej zakończeniem. Wykonanie tych testów silnie wpłynie na twój projekt, rzucając wyzwanie szarej strefie i rzucając ją w rzeczywistość na długo przed ukończeniem produktu. zmuszając cię często do powrotu do projektowania i dostosowania go, aby to uwzględnić.
Testuj i projektuj ... to samo
Moim zdaniem TDD po prostu wprowadza test jako integralną część projektu zamiast czegoś zrobionego na końcu, aby go zweryfikować. Kiedy zaczynasz używać TDD coraz bardziej, zastanawiasz się, jak zniszczyć / zepsuć system podczas jego projektowania. Osobiście nie zawsze najpierw wykonuję testy. Pewnie, że wykonuję oczywiste (jednostkowe) testy interfejsu, ale prawdziwe korzyści płyną z testów integracji i specyfikacji, które tworzę, gdy myślę o nowym i kreatywnym sposobie, w jaki ten projekt może się zepsuć. Jak tylko wymyślę sposób, koduję test i sprawdzam, co się stanie. Czasami mogę żyć z konsekwencjami, w tym przypadku test przenoszę w osobnym projekcie, który nie jest częścią głównej kompilacji (ponieważ nadal będzie nieudany).
Więc kto prowadzi program?
W TDD napędzany tutaj oznacza po prostu, że twoje testy wpływają tak silnie na twój projekt, że można poczuć, że faktycznie nim sterują. Jednak na tym się kończy, a tutaj rozumiem wasze obawy, to trochę przerażające ... kto prowadzi serial?
TY jeździsz, a nie testy. Testy są po to, abyś, idąc dalej, zyskał dobry poziom pewności co do tego, co stworzyłeś, dzięki czemu możesz dalej budować, wiedząc, że opiera się on na solidnych podstawach.
stałe, o ile testy są stałe
Właśnie dlatego napędzany TDD. To nie tyle testy napędzają całą sprawę, ale będą miały tak głęboki wpływ na to, jak robisz, na to, jak projektujesz i myślisz, że Twój system przekaże dużą część procesu myślowego na testy i w zamian będą miały głęboki wpływ na twój projekt.
tak, ale jeśli zrobię to z moim mostem, to ...
zatrzymaj się tutaj ... inżynieria oprogramowania BARDZO różni się od innych praktyk inżynieryjnych. W rzeczywistości inżynieria oprogramowania ma o wiele więcej wspólnego z literaturą. Można wziąć skończoną książkę, zedrzeć z niej 4 rozdziały i napisać dwa nowe rozdziały, aby je zastąpić i włożyć z powrotem do książki, a nadal masz dobrą książkę. Dzięki dobrym testom i oprogramowaniu możesz zgrać dowolną część systemu i zastąpić ją inną, a koszt takiego działania nie jest znacznie wyższy niż w przypadku tworzenia go. W rzeczywistości, jeśli wykonałeś testy i pozwoliłeś im wystarczająco wpłynąć na twój projekt, może to być znacznie tańsze niż tworzenie go w pierwszej kolejności, ponieważ będziesz mieć pewien poziom pewności, że ta zamiana nie złamie tego, co obejmują testy.
Jeśli to takie dobre, dlaczego nie zawsze działa?
Ponieważ testowanie wymaga BARDZO innego sposobu myślenia niż budowanie. Nie każdy jest w stanie się wycofać i zrezygnować, w rzeczywistości niektórzy ludzie nie będą w stanie zbudować odpowiednich testów po prostu dlatego, że nie mogą zmusić się do zniszczenia swojego dzieła. Dzięki temu projekty będą miały za mało testów lub testów wystarczających do osiągnięcia metryk docelowych (przychodzi na myśl pokrycie kodu). Będą zadowoleni z testów ścieżki i testów wyjątków, ale zapomną o przypadkach narożnych i warunkach brzegowych.
Inni polegają tylko na testach rezygnacji z projektowania częściowo lub całkowicie. Każdy członek robi to, a następnie integruje się ze sobą. Design jest przede wszystkim narzędziem komunikacji, stawkami, które stawiamy w ziemi, aby powiedzieć, że tam będę, szkice, które mówią, że tam będą drzwi i okna. Bez tego twoje oprogramowanie jest skazane na zagładę, niezależnie od tego, ile testów poddasz. Integracja i fuzje zawsze będą bolesne i nie będą miały testów na najwyższym poziomie abstrakcji.
W przypadku tych drużyn TDD może nie być dobrym rozwiązaniem.
źródło
Dzięki TDD zwykle nie piszesz kodu, który nie jest łatwy ani szybki do przetestowania. To może wydawać się drobiazgiem, ale może mieć głęboki wpływ na projekt, ponieważ wpływa na to, jak łatwo refaktoryzować, testować, odtwarzać błędy za pomocą testów i weryfikować poprawki.
Łatwiej jest także nowemu programistowi przyśpieszyć działanie, gdy lepiej uwzględniamy kod obsługiwany przez testy.
źródło
Dużo o tym myślałem, chociaż sam nie ćwiczę TDD. Wydaje się, że istnieje (silna?) Dodatnia korelacja między jakością kodu a śledzeniem TDD.
1) Moje pierwsze podejście jest takie, że (przede wszystkim) nie jest to spowodowane tym, że TDD dodaje „lepszą jakość” do kodu (jako takiego), to bardziej, że TDD pomaga wyeliminować najgorsze części i nawyki, a tym samym pośrednio zwiększyć jakość.
Powiedziałbym nawet, że to nie jest sam test - to proces pisania tych testów. Trudno jest pisać testy na zły kod i odwrotnie. A trzymanie tego z tyłu głowy podczas programowania eliminuje wiele złego kodu.
2) Innym punktem widzenia (który staje się filozoficzny) jest podążanie za mentalnymi nawykami mistrza. Nie uczysz się mistrza, postępując zgodnie z jego „zewnętrznymi nawykami” (np. Długa broda jest dobra), musisz nauczyć się jego wewnętrznych sposobów myślenia, a to jest trudne. A w jakiś sposób sprawiając, że (nowi) programiści podążają za TDD, dostosowują swoje sposoby myślenia bliżej mistrza.
źródło
Wygląda na to, że masz błędne przekonanie dotyczące zarówno refaktoryzacji, jak i TDD.
Dlatego nie można refaktoryzować kodu, dopóki nie przejdzie.
A TDD, a konkretnie testowanie jednostkowe (które uważam za usprawnienie rdzenia, ponieważ inne testy wydają mi się prawdopodobne), nie polega na przeprojektowaniu komponentu, dopóki nie zadziała. Chodzi o zaprojektowanie komponentu i pracę nad implementacją, aż komponent będzie działał zgodnie z przeznaczeniem.
Ważne jest również, aby naprawdę zrozumieć, że testy jednostkowe dotyczą testowania jednostek . Ze względu na tendencję do pisania wielu rzeczy od zera ważne jest, aby testować takie jednostki. Inżynier budownictwa zna już specyfikacje jednostek, których używa (różne materiały) i może oczekiwać, że będą działać. Są to dwie rzeczy, które często nie dotyczą inżynierów oprogramowania i bardzo pro-inżynierskie jest testowanie jednostek przed ich użyciem, ponieważ oznacza to stosowanie przetestowanych, wysokiej jakości komponentów.
Gdyby inżynier budownictwa wpadł na pomysł, aby wykorzystać nową tkankę z włókien do wykonania dachu na pokrycie stadionu, można by się spodziewać, że przetestuje go jako jednostkę, tj. Zdefiniuje potrzebne specyfikacje (np. Wagę, przepuszczalność, stabilność itp.) Oraz następnie przetestuj i dopracuj go, aż się spełni.
Właśnie dlatego działa TDD. Ponieważ jeśli zbudujesz oprogramowanie testowanych urządzeń, szanse są znacznie lepsze, gdy połączysz je ze sobą, a jeśli nie, możesz spodziewać się, że problem znajdzie się w kodzie kleju, zakładając, że twoje testy mają dobry zasięg.
edycja:
Refaktoryzacja oznacza: brak zmian w funkcjonalności. Jednym z punktów pisania testu jednostkowego jest upewnienie się, że refaktoryzacja nie złamie kodu. TDD ma więc na celu zapewnienie, że refaktoryzacja nie ma skutków ubocznych.
Ziarnistość nie jest przedmiotem perspektywy, ponieważ, jak powiedziałem, testy jednostkowe testują jednostki, a nie systemy, dzięki czemu ziarnistość jest dokładnie zdefiniowana.
TDD zachęca do dobrej architektury. Wymaga to zdefiniowania i wdrożenia specyfikacji dla wszystkich jednostek, co zmusi cię do zaprojektowania ich przed wdrożeniem, co jest zupełnie sprzeczne z tym, co myślisz. TDD dyktuje tworzenie jednostek, które mogą być testowane indywidualnie, a zatem są całkowicie oddzielone.
TDD nie oznacza, że rzucam test oprogramowania na kod spaghetti i mieszam makaron, aż przejdzie.
W przeciwieństwie do inżynierii lądowej, w inżynierii oprogramowania projekt zwykle stale ewoluuje. W inżynierii lądowej musisz zbudować most w pozycji A, który może unieść x ton i jest wystarczająco szeroki dla n pojazdów na godzinę.
W inżynierii oprogramowania klient może w zasadzie zdecydować w dowolnym momencie (być może po ukończeniu), chce mostu dwupiętrowego i że chce go połączyć z najbliższą autostradą, i że chciałby, aby był to most podnoszony, ponieważ jego firma niedawno zaczął korzystać ze statków żaglowych.
Inżynierowie oprogramowania mają za zadanie zmieniać projekty. Nie dlatego, że ich projekty są wadliwe, ale dlatego, że taki jest sposób działania. Jeśli oprogramowanie jest dobrze zaprojektowane, można je przeprojektować na wysokim poziomie, bez konieczności przepisywania wszystkich komponentów niskiego poziomu.
TDD polega na tworzeniu oprogramowania z indywidualnie testowanymi, wysoce odsprzężonymi komponentami. Dobrze wykonany, pomoże ci reagować na zmiany wymagań znacznie szybciej i bezpieczniej niż bez niego.
TDD dodaje wymagania do procesu rozwoju, ale nie zabrania innych metod zapewniania jakości. To prawda, że TDD nie zapewnia takiego samego bezpieczeństwa jak weryfikacja formalna, ale z drugiej strony weryfikacja formalna jest niezwykle kosztowna i niemożliwa do zastosowania na poziomie systemu. A jednak, jeśli chcesz, możesz połączyć oba.
TDD obejmuje również testy inne niż testy jednostkowe, które są przeprowadzane na poziomie systemu. Uważam je za łatwe do wyjaśnienia, ale trudne do wykonania i trudne do zmierzenia. Są również całkiem prawdopodobne. Choć absolutnie widzę ich konieczność, tak naprawdę nie cenię ich jako pomysłów.
W końcu żadne narzędzie nie rozwiązuje problemu. Narzędzia ułatwiają jedynie rozwiązywanie problemu. Możesz zapytać: W jaki sposób dłuto pomoże mi w świetnej architekturze? Cóż, jeśli planujesz robić proste ściany, proste cegły są pomocne. I tak, oczywiście, jeśli dasz to narzędzie idiocie, prawdopodobnie w końcu przebije go stopą, ale to nie wina dłuta, ponieważ nie jest to wada TDD, że daje fałszywe bezpieczeństwo nowicjuszom, którzy nie piszą dobrych testów.
Podsumowując, można powiedzieć, że TDD działa znacznie lepiej niż brak TDD.
źródło
Nie podoba mi się to, że „test, a nie użytkownik, określa wymagania”. Myślę, że bierzesz pod uwagę tylko testy jednostkowe w TDD, podczas gdy obejmuje to również testy integracyjne.
Oprócz testowania bibliotek tworzących bazę oprogramowania, napisz testy obejmujące interakcje użytkowników z oprogramowaniem / witryną / czymkolwiek. Pochodzą one bezpośrednio od użytkowników, a biblioteki takie jak ogórek (http://cukes.info) mogą nawet pozwolić użytkownikom pisać testy samodzielnie, w języku naturalnym.
TDD zachęca również do elastyczności kodu - jeśli spędzasz wieczność na projektowaniu architektury czegoś, będzie bardzo trudno wprowadzić te zmiany później, jeśli to konieczne. Zacznij od napisania kilku testów, a następnie napisz trochę kodu, który przejdzie te testy. Dodaj więcej testów, dodaj więcej kodu. Jeśli konieczna jest radykalna zmiana kodu, testy nadal trwają.
I w przeciwieństwie do mostów i samochodów, jeden kawałek oprogramowania może ulegać ogromne zmiany w ciągu jego trwania, i robi złożoną refaktoryzacji bez konieczności testy pisemne pierwszy jest po prostu prosi się o kłopoty.
źródło
Myślę, że zbliżasz się do pierwszego punktu pod niewłaściwym kątem.
Z teoretycznego punktu widzenia udowadniamy, że coś działa, sprawdzając pod kątem punktów awarii. To jest zastosowana metoda. Może istnieć wiele innych sposobów na udowodnienie, że coś działa, ale TDD ustaliło się ze względu na prostotę swojego podejścia bitowego: jeśli się nie zepsuje, działa.
W praktyce oznacza to wprost otwarcie: możemy teraz przejść do następnej rzeczy (po pomyślnym zastosowaniu TDD w celu spełnienia wszystkich predykatów). Jeśli podchodzisz do TDD z tej perspektywy, to nie chodzi o „pisanie testów + refaktoryzacja do zaliczenia”, chodzi raczej o to, żeby to ukończyć, teraz całkowicie skupiam się na kolejnej funkcji, która jest teraz najważniejsza .
Zastanów się, jak to odnosi się do inżynierii lądowej. Budujemy stadion, który może pomieścić publiczność liczącą 150000 osób. Po tym, jak udowodniliśmy, że integralność strukturalna stadionu jest dobra, najpierw zadbaliśmy o bezpieczeństwo . Możemy teraz skupić się na innych kwestiach, które stają się natychmiast ważne, takich jak toalety, stojaki z jedzeniem, miejsca siedzące itp., Dzięki czemu wrażenia publiczności są przyjemniejsze. Jest to nadmierne uproszczenie, ponieważ TDD ma o wiele więcej, ale sedno polega na tym, że nie zapewniasz najlepszej możliwej obsługi, jeśli skupiasz się zarówno na nowych, jak i ekscytujących funkcjach, zachowując jednocześnie integralność. W obu przypadkach dostajesz go w połowie drogi. To znaczy, skąd możesz dokładnie wiedzieć, jakwiele toalet i gdzie powinieneś pomieścić 150000 osób? Rzadko widywałem zawalenie się stadionów za mojego życia, ale przy wielu okazjach musiałem czekać w kolejce w przerwie. Oznacza to, że problem z toaletą jest prawdopodobnie bardziej złożony i jeśli inżynierowie mogą poświęcić mniej czasu na bezpieczeństwo, mogą w końcu rozwiązać problem z toaletą.
Twoja druga uwaga jest nieistotna, ponieważ już ustaliliśmy, że absoluty są głupcami i ponieważ Hank Moody mówi, że nie istnieją (ale nie mogę znaleźć odniesienia do tego).
źródło
TDD w inżynierii oprogramowania jest dobrą praktyką, podobnie jak obsługa błędów w aplikacjach jest dobrą praktyką, a także rejestrowaniem i diagnostyką (chociaż jest to część obsługi błędów).
TDD nie może być wykorzystywany jako narzędzie redukujące rozwój oprogramowania do wersji próbnej i kodowania błędów. Jednak większość programistów patrzy na dzienniki środowiska uruchomieniowego, obserwuje wyjątki w debuggerze lub używa innych oznak niepowodzenia / sukcesu podczas fazy programowania, która polega na kodowaniu / kompilowaniu / uruchamianiu aplikacji - przez cały dzień.
TDD to tylko sposób na sformalizowanie i zautomatyzowanie tych kroków, aby zwiększyć produktywność jako programisty.
1) Nie można porównywać inżynierii oprogramowania do budowy mostów, elastyczność w budowie mostów nie jest w żaden sposób zbliżona do projektowania oprogramowania. Konstruowanie mostu jest jak pisanie tego samego programu w kółko na stratnej maszynie. Mostów nie można powielać ani używać ponownie, tak jak oprogramowanie. Każdy most jest wyjątkowy i musi zostać wyprodukowany. To samo dotyczy samochodów i innych konstrukcji.
Najtrudniejszą rzeczą w inżynierii oprogramowania jest odtwarzanie błędów, kiedy awaria mostu jest zwykle bardzo łatwa do ustalenia, co poszło nie tak, i teoretycznie łatwe jest odtworzenie awarii. Gdy program komputerowy zawiedzie, może to być złożony łańcuch zdarzeń, który doprowadził system do stanu wadliwego i bardzo trudno jest ustalić, gdzie jest błąd. TDD i testy jednostkowe ułatwiają testowanie odporności komponentów oprogramowania, bibliotek i algorytmów.
2) Stosowanie słabych testów jednostkowych i płytkich przypadków testowych, które nie obciążają systemu do budowania fałszywego poczucia pewności, jest po prostu złą praktyką. Ignorowanie architektonicznej jakości systemu i po prostu wypełnienie testów jest oczywiście równie złe. Ale oszustwo na budowie drapacza chmur lub mostu w celu zaoszczędzenia materiału i nieprzestrzegania planów jest równie złe i zdarza się cały czas ...
źródło
Jeśli zaakceptujesz, że im szybciej zostaną znalezione błędy, tym mniejszy koszt ich naprawy, to samo to sprawia, że TDD jest opłacalne.
źródło
TDD tak naprawdę nie polega na testowaniu. I z pewnością nie zastąpi dobrych testów. To, co daje ci, to przemyślany projekt , łatwy do konsumpcji przez konsumenta, łatwy w utrzymaniu i refaktoryzującym później. To z kolei prowadzi do mniejszej liczby błędów i lepszego, bardziej elastycznego projektowania oprogramowania. TDD pomaga również przemyśleć i udokumentować swoje założenia, często stwierdzając, że niektóre z nich były nieprawidłowe. Dowiesz się o tym bardzo wcześnie.
Dodatkową zaletą jest duży zestaw testów, które można uruchomić, aby upewnić się, że refaktoryzacja nie zmieni zachowania (danych wejściowych i wyjściowych) oprogramowania.
źródło
Dam ci krótką odpowiedź. Zazwyczaj TDD jest postrzegane w niewłaściwy sposób, podobnie jak testy jednostkowe. Nigdy nie rozumiałem testów jednostkowych aż do niedawna po obejrzeniu dobrej rozmowy wideo na temat technologii. Zasadniczo TDD stwierdza tylko, że chcesz DZIAŁAĆ następujące rzeczy. MUSZĄ zostać wdrożone. Następnie projektujesz resztę oprogramowania w normalny sposób.
To trochę jak pisanie przypadków użycia biblioteki przed jej zaprojektowaniem. Tyle że możesz zmienić przypadek użycia w bibliotece i możesz tego nie zrobić dla TDD (używam TDD do projektowania API). Zachęcamy również do dodania więcej testów i pomyśl o dzikich wejściach / zastosowaniach, jakie może uzyskać test. Uważam, że jest to przydatne podczas pisania bibliotek lub interfejsów API, w których jeśli coś zmienisz, musisz wiedzieć, że coś zepsułeś. W większości codziennych programów nie przeszkadza mi to, dlaczego potrzebuję skrzynki testowej dla użytkownika, który naciska przycisk lub jeśli chcę zaakceptować listę CSV lub listę z jednym wpisem w wierszu ... To nie ma znaczenia, jestem dozwolony aby to zmienić, nie powinienem / nie mogę używać TDD.
źródło
Oprogramowanie jest organiczne, gdy inżynieria budowlana jest konkretna.
Kiedy zbudujesz swój most, pozostanie on mostem i jest mało prawdopodobne, że w krótkim czasie przekształci się w coś innego. Ulepszenia będą wprowadzane przez miesiące i lata, ale nie godziny i dni, jak w oprogramowaniu.
Podczas testowania w izolacji zwykle można użyć dwóch rodzajów ram. Ograniczone ramy i nieograniczone. Nieograniczone frameworki (w .NET) pozwalają testować i zastępować wszystko, niezależnie od modyfikatorów dostępu. Tj. Możesz upuszczać i wyśmiewać prywatne i chronione elementy.
Większość projektów, które widziałem, wykorzystuje ograniczone struktury (RhinoMocks, NSubstitute, Moq). Podczas testowania przy użyciu tych środowisk należy zaprojektować aplikację w taki sposób, aby można było wstrzykiwać i zastępować zależności w czasie wykonywania. Oznacza to, że musisz mieć luźno sprzężoną konstrukcję. Luźno sprzężona konstrukcja (przy prawidłowym wykonaniu) oznacza lepsze rozdzielenie problemów, co jest dobrą rzeczą.
Podsumowując, uważam, że za tym stoi myśl, że jeśli twój projekt jest testowalny, to jest luźno powiązany i ma dobry podział problemów.
Na marginesie, widziałem aplikacje, które były naprawdę testowalne, ale źle napisane z perspektywy projektowania obiektowego.
źródło
Nie ma
Wyjaśnienie: testy automatyczne są lepsze niż brak testów. Jednak osobiście uważam, że większość testów jednostkowych jest marnotrawstwem, ponieważ zwykle są one tautologiczne (tzn. Mówią rzeczy oczywiste z rzeczywistego testowanego kodu) i nie można łatwo udowodnić, że są one spójne, niepotrzebne i obejmują wszystkie przypadki graniczne (w których zwykle występują błędy ).
I najważniejsze: dobre projektowanie oprogramowania nie wypada magicznie z testów, ponieważ jest reklamowane przez wielu ewangelistów zwinnych / TDD. Każdy, kto twierdzi inaczej, powinien podać linki do recenzowanych badań naukowych, które to potwierdzają, lub przynajmniej odniesienie do jakiegoś projektu open source, w którym korzyści z TDD można potencjalnie zbadać na podstawie historii zmian kodu.
źródło