Dlaczego działa TDD? [Zamknięte]


92

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:

  1. 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.
  2. 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.


53
Mosty, samochody i inne projekty fizyczne nie są tak plastyczne jak oprogramowanie. Jest to ważne rozróżnienie i oznacza, że ​​porównania między oprogramowaniem a prawdziwą inżynierią nie zawsze są istotne. To, co działa w przypadku mostów, może nie działać w przypadku oprogramowania i odwrotnie.
Lars Wirzenius

9
W pewnym stopniu zgadzam się z twoimi wątpliwościami. Muszę na przykład wyznać, że mam wrażenie, że posiadanie zestawu testów może mieć efekt uboczny w jakiś sposób „łagodzący” uwagę podczas pisania kodu. Oczywiście testy są dobrą rzeczą (obowiązkową, jeśli chcesz mieć możliwość refaktoryzacji), ale tylko wtedy, gdy uzupełniają uwagę na szczegóły, przypadki graniczne, wydajność lub rozszerzalność, a nie, jeśli ją zastępują.
6502

2
@ 6502: Na pewno! TDD nie jest srebrną kulą i nie rozwiąże wszystkich problemów pojawiających się podczas tworzenia oprogramowania. Jest to jednak przydatna metoda organizowania przepływu pracy. Możesz na przykład nałożyć wymóg, aby wszystkie przypadki graniczne były objęte testami. Nadal musisz wiedzieć, jakie są te przypadki graniczne, ale teraz masz również narzędzie do sprawdzenia, czy Twój kod radzi sobie z nimi poprawnie.
Mchl 30.01.11

2
@CesarGon, możesz być także zainteresowany pytaniem, które zadałem jakiś czas temu SO ... Niezupełnie TDD, ale powiązane ... Niektóre bardzo pouczające odpowiedzi.
AviD

6
Jak niesamowite jest to, że analog inżynierii lądowej / rozwoju oprogramowania nie wytrzymuje. W tej samej linii często zauważyłem, że nie mogę gotować naleśników w taki sam sposób, jak kosię trawnik.

Odpowiedzi:


66

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.


7
+1 za mówienie o tym, gdzie występują testy w produkcji. Świetny punkt
Adam Lear

11
Mówisz „części są testowane”. Jasne, ale nie zaprojektowane testowo. Część samolotowa nie została zaprojektowana w sposób testowy, ale w sposób architektoniczny z dużym wyprzedzeniem. Podobieństwa z TDD nie istnieją tutaj.
CesarGon 30.01.11

3
Dodając do tego: moim zdaniem TDD dotyczy przede wszystkim sposobów upewnienia się, że możesz sprawdzić części, a nie dużej „wszystko albo nic” na końcu. Ale adagium TDD: „najpierw zbuduj test” nie ma oznaczać „wykonaj test, zanim pomyślisz o tym, co chcesz osiągnąć”. Ponieważ myślenie o teście JEST częścią projektowania. Określanie, co chcesz dokładnie zrobić, to projektowanie. Zanim zaczniesz pisać, już zaprojektowałeś. (W ten sposób myślę, że termin „projektowanie oparte na testach” wprowadza w błąd, sugerując jednokierunkową ścieżkę, gdzie tak naprawdę jest to pętla sprzężenia zwrotnego).
Inca

2
+1: Oprogramowanie to wyłącznie projektowanie. Analogia mostu w pytaniu jest całkowicie błędna. TDD całkowicie stosuje się do testów zewnętrznych. Projektowanie oparte na testach dotyczy wszystkich warstw projektu.
S.Lott,

3
@CesarGon: Nie, TDD napędza ROZWÓJ poprzez testy. Różni się to od kierowania projektem. Projekt decyduje o sposobie korzystania z systemu, a tym samym o testach, które należy wdrożyć, aby odtworzyć to zachowanie. Jednak wdrożenie tych testów często pomaga dopracować projekt.
deworde

26

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.

Seibel: A co z pomysłem wykorzystania testów do napędzania projektowania?

Norvig: Widzę testy bardziej jako sposób korygowania błędów niż jako sposób projektowania. To ekstremalne podejście polegające na powiedzeniu: „Cóż, pierwszą rzeczą, którą robisz, jest napisanie testu, który mówi, że na końcu otrzymuję prawidłową odpowiedź”, a następnie uruchamiasz go i widzisz, że to się nie udaje, a następnie mówisz: „Co mam zrobić? potrzebujesz dalej? ”- nie wydaje mi się to dobrym sposobem na zaprojektowanie czegoś. Wydaje się, że tylko gdyby to było tak proste, że rozwiązanie zostało z góry ustalone, miałoby to sens. Myślę, że najpierw musisz o tym pomyśleć. Musisz powiedzieć: „Jakie są kawałki? Jak napisać testy dla kawałków, dopóki nie dowiem się, jakie są niektóre z nich? ”A potem, kiedy to zrobisz, dobrze jest zdyscyplinować testy dla każdego z nich i dobrze zrozumieć, w jaki sposób współdziałają ze sobą oraz przypadki graniczne i tak dalej. Wszystkie powinny mieć testy. Ale nie sądzę, że kierujesz całym projektem, mówiąc: „Ten test się nie powiódł”.


7
Teraz, jeśli well, you haven't done TDD right!
przekażesz

10
I mieliby rację. Robimy BDD / TDD na systemie o bardzo dużej głośności i działa dobrze. Testy mają na celu stwierdzenie, że złamałeś oczekiwane zachowanie. Jeśli idziesz i zmieniasz to później „przełamując” testy, w rzeczywistości robisz to źle. Testy należy najpierw zmienić, aby ugruntować NOWE zachowanie systemu, a następnie je zmienić. I tak, jeśli robisz to dobrze, piszesz testy zaczynając od „co ta rzecz musi zrobić”, a proces pisania testu pomaga ci pomyśleć „co IT musi zrobić, aby wykonać swoją pracę”. Aha, i nigdy nie korzystano z usług konsultantów ...
Andy

4
Wykonanie wielu testów nie zwalnia z tworzenia odpowiedniego projektu. Jest wysoce sprzężona, niezależnie od tego, ile testów jest wokół niej zbudowanych i zawsze będzie delikatna. testy osadzania w tym projekcie mogą bardzo pogorszyć sytuację.
Newtopian

3
Nie chodzi o to, żeby zrobić to źle, czy być bardzo sprzężonym projektem. Faktem jest, że interfejsy się zmieniają. Oznacza to, że wszystkie testy używające tego interfejsu muszą się zmienić. W dużych systemach synchronizacja testów z wymaganymi zmianami może zacząć przytłaczać implementację. Staje się to jeszcze większym problemem, jeśli wykonujesz zwinny rozwój, ponieważ szanse na zmiany interfejsu są znacznie bardziej prawdopodobne. To zabawne, jak kiedy metodologie nie działają, zwolennicy metodologii twierdzą, że robisz to źle. Bardziej prawdopodobne jest, że metodyka ta nie jest odpowiednia dla wszystkich domen problemowych.
Dunk

2
Z mojego doświadczenia wynika, że ​​TDD działa dla małych aplikacji lub modułów. Kiedy muszę pracować nad czymś złożonym, TDD spowalnia mnie, ponieważ zmusza mnie do napisania szczegółowej (uruchamialnej) specyfikacji, zanim uzyskałem ogólny obraz w mojej głowie: więc zbyt wcześnie się zagubiłem w szczegółach i często muszę wyrzuć całą masę testów, jeśli dowiem się, że nie potrzebuję pewnych klas (wciąż bawię się projektem). W takich przypadkach wolę najpierw uzyskać rozsądny ogólny projekt, a następnie dopracować szczegóły implementacji (być może przy użyciu TDD).
Giorgio

25

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

  1. ŻE kod nazywany jest pełną specyfikacją, ponieważ oczekiwane wyniki znajdują się dokładnie w przypadkach testowych. Kontrola wzrokowa (która oczekuje, że przypadki testowe przejdą) może natychmiast powiedzieć „och, ten test sprawdza, czy wywołanie faktury przez firmę w takiej sytuacji powinno dać TEN wynik”.
  2. JAK należy wywołać kod. Rzeczywiste kroki potrzebne do przeprowadzenia testów są określone bezpośrednio, bez żadnego zewnętrznego rusztowania (bazy danych są wyśmiewane itp.).

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


5
Dodałbym do tego, że faktycznie masz dość rozsądne i jasne wytyczne dotyczące tego, kiedy skończysz. Bez jakiejś jasnej procedury obiektywnego sprawdzenia, czy wykonałeś dane zadanie, trudno jest je poznać. Moje własne doświadczenie obejmuje wiele godzin i dni zmarnowanych na „negocjowanie”, czy zadanie zostało ukończone, oraz ciągłe, ciągłe przesuwanie linii. Wpływa to na wszystkie poziomy zarządzania projektami, w tym planowanie, w jaki sposób możesz zaplanować takie zadanie? Wyraźniejsze cele z szybszym czasem realizacji zwiększają przepustowość ORAZ komunikację.
Edward Strange

To powinna być zaakceptowana odpowiedź.
Niing

19

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:

„Mamy te dwa kawałki metalu połączone ze sobą, a połączenie musi wytrzymać siły ścinające rzędu x. Sprawdźmy, która metoda połączenia jest najlepsza do tego celu ”

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:

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

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

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


Jeśli dobrze cię rozumiem, mówisz, że TDD jest OK, o ile (a) jest używany tylko do testów jednostkowych i (b) towarzyszy mu również inne podejście testowe. W takim przypadku może adresować punkt 2 w PO. Jak byś adresował punkt 1?
CesarGon 30.01.11

@CesarGon: TDD działa również świetnie w testach integracyjnych.
sevenseacat

Punkt 1 sprowadza się do tego, że zanim projekt końcowy samochodu lub mostu zostanie zaakceptowany, przechodzi wiele powtórzeń, podczas których wszystkie jego szczegóły są sprawdzane i testowane pod kątem wymagań nałożonych przez „plan szerokiego zakresu”. Odbywa się to głównie na papierze (lub w pamięci komputera), ponieważ w tym przypadku jest to tańsze, ale zauważ, że często budowane są fizyczne prototypy zarówno całej konstrukcji (być może nie w przypadku mostka), jak i jej komponentów.
Mchl 30.01.11

@Karpie: I do testów akceptacyjnych! Powinieneś wcześniej wiedzieć, co jest wymagane, aby Twoja praca została zaakceptowana przez klienta.
Mchl 30.01.11

1
Ok więc. Prawie pierwszym zespołem, który rozpoczął pracę, jest zespół architektów, którym powiedziano, aby zaprojektowali most zdolny do spełnienia kryteriów klientów, a jednocześnie jest tani i prawdopodobnie dobrze wygląda i nie schodzi przy pierwszym silniejszym podmuchu wiatru. Zespół może zaproponować kilka wstępnych projektów mniej więcej spełniających te kryteria, a następnie wybrać jeden i pracować nad nim bardziej szczegółowo, powtarzać, powtarzać, powtarzać, aż projekt będzie gotowy (tj. Spełni podane kryteria i będzie wystarczająco szczegółowy, aby można rozpocząć kolejne etapy projektu)
Mchl

18

Moim zdaniem TDD działa, ponieważ

  • Zmusza to użytkownika do zdefiniowania tego, co ma robić jednostka, przed podjęciem decyzji o wdrożeniu na poziomie precyzji, która zazwyczaj nie jest objęta żadnym dokumentem specyfikacji ani wymagań
  • Dzięki temu kod z natury może zostać ponownie użyty, ponieważ należy go używać zarówno w testach, jak i scenariuszach produkcyjnych
  • Zachęca do pisania kodu w mniejszym narzędziu do testowania fragmentów, co prowadzi do lepszych projektów

W szczególności na zdobywane punkty

  • Kod jest bardziej plastyczny niż cegła lub stal, więc modyfikacja jest tańsza. Jeszcze taniej jest, jeśli masz testy, aby upewnić się, że zachowanie się nie zmieniło
  • TDD nie jest wymówką, aby nie projektować - architektura wysokiego poziomu jest nadal ogólnie zalecana, ale nie zawiera zbyt wielu szczegółów. Projekt Big Up Front jest odradzany, ale zachęca się do robienia wystarczającej ilości projektów
  • TDD nie może zagwarantować, że system działa, ale zapobiega prześlizgnięciu się wielu małych błędów, które w przeciwnym razie zostałyby pominięte. Również dlatego, że ogólnie zachęca do lepiej ustrukturyzowanego kodu, często jest łatwiejszy do zrozumienia, więc mniej prawdopodobne jest, że zostanie uszkodzony

3
Powinieneś także dodać, że w miarę wykrycia wad możesz mieć pewność, że nie zostaną one powtórzone, ponieważ dodasz kolejny test.
Andy,

16

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

public class PersonTest:Test
{
   [Test]
   TestNameProperty()
   {
      var person=new Person();
      person.Name="John Doe";
      Assert.AreEqual("John Doe", person.Name);
   }
}

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.


4
Wartość czerwonych testów wykrywających błędy jest ogólnie atrybutem testów jednostkowych, a nie TDD.
Robert Harvey

2
Masz rację w tym punkcie. Ale prawdopodobieństwo, że miałbym ten konkretny błąd objęty testowaniem jednostkowym post-hoc, jest niższe.
Michael Brown

1
Czy możesz poprzeć to twierdzenie za pomocą pewnych dowodów, danych lub rzetelnej analizy?
CesarGon

1
@CesarGon to badanie , podczas gdy programiści pracujący nad małym projektem, sugerują, że programiści używający TDD produkują kod z lepszym zakresem testów niż ci, którzy testują po fakcie (92% -98% vs 80% -90%) i w konsekwencji łapią więcej wady podczas programowania (o 18% mniej wad znaleziono w kodzie wyprodukowanym przy użyciu TDD).
Jules

11

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.


+1 Dzięki za wyczerpującą odpowiedź, Noah. Zgadzam się, że główna różnica między TDD a nie TDD polega na tym, że testy są pisane. Myślę jednak również, że pierwsze „D” w TDD oznacza „napędzany”, co oznacza, że ​​w TDD cały rozwój jest napędzany przez testy. To jest najbardziej zagadkowe. Nie mam problemów z pisaniem testów przed skonstruowaniem tego, co będzie testowane. Ale pozwalanie na testy? Czym różni się to od zielonego światła, aby cokolwiek robić, o ile powierzchowne (tj. Wynik) jest w porządku?
CesarGon 30.01.11

Cóż, Cesar, co zaproponowałbyś jako lepsze, obiektywne kryteria decydujące o zakończeniu zadania programistycznego? Jeśli, podobnie jak w TDD, test jest specyfikacją, na którą programista celuje, to programista wykonał swoją pracę po przejściu testu, nie? Tak, mogą występować wady w teście, tak jak mogą być wady w dowolnej specyfikacji. Nie jest to jednak zadanie programistów. Jeśli test jest wadliwy, to zostaje naprawiony, a następnie programista celuje w nowy cel, a kiedy wszystko jest zielone, jest gotowy. Działa, ponieważ ZAWSZE istnieje test do zaliczenia ... bez dodatkowego, nieudokumentowanego puchu.
Edward Strange

3
Może nie wyraziłem się jasno. Testy mogą być dobrym sposobem na określenie, kiedy skończysz. Ale nie sądzę, że są dobrym sposobem na decyzję, co musisz zbudować. W TDD stwierdziłem, że ludzie używają testów, aby zdecydować, co mają zbudować. Czy to również twoje doświadczenie?
CesarGon

Nie. Nasze kompilacje są zautomatyzowane. Są uruchamiane przez zmiany. Jak powiedziałem, TDD to tylko część rozwiązania.
Edward Strange

9

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.


7

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.


2
Podoba mi się to - podkreśla fakt, że nie tyle TDD, który tworzy korzyści (choć testy jednostkowe mają oczywiście ogromną wartość), ale rodzaj kodu, który produkuje w tym sensie, że jest testowalny (w izolacji) i wynikają z tego różne dobre rzeczy (rozdzielenie obaw, IoC i zastrzyk uzależnienia itp.)
Murph

1
@Murph yeah TDD pomaga zachować uczciwość :)
Alb

1
Szczerze mówiąc, tak naprawdę nie przekonuje mnie argument „łatwiej jest przyspieszyć” - testy mogą być pomocne, ale kod (jako całość, niekoniecznie w izolacji) może być nieco trudniejszy do odkodowania, ponieważ niektóre rzeczy wyglądają jakby magicznie, np. nie wiesz, jakiej implementacji IInjectedThing używasz.
Murph

@Murph Teoria jest taka, że ​​implementacja IInjectedThing jest również dobrze zaprojektowana i objęta dobrymi testami, więc tak naprawdę nie musisz wiedzieć, co to jest, aby zrozumieć klasę, do której została wstrzyknięta.
Adam Lear

@Anna - tak, do pewnego stopnia ... jeśli próbujesz dowiedzieć się, gdzie coś jest zepsute (zawsze uważam, że polowanie na błędy jest dobrym sposobem na znalezienie podstaw w projekcie) lub gdzie coś trzeba zmienić / dodał, że musisz wiedzieć gdzie. Nawet jeśli to miejsce jest dobrze zamknięte, wciąż musisz to znaleźć ... a jeśli oznacza to zamianę czegoś (nowa implementacja IWhatsit), musisz wiedzieć, jak korzystać z alternatywnej implementacji. Ponownie nie przeczę, że konstrukcja jest zła - zbyt wiele dowodów przeciwnych - raczej sugeruję, że niektóre rzeczy mogą być mniej oczywiste.
Murph,

5

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.


+1 Myślę, że go przybiłeś, Maglob. Szczególnie podoba mi się twoje wyjaśnienie, że „TDD pomaga wyeliminować najgorsze części i nawyki, [...] pośrednio podnosząc jakość”. Analogia długiej brody też jest bardzo dobra.
CesarGon 30.01.11

nie piszesz testów na zły kod, ale piszesz test, a następnie piszesz kod, aby test przeszedł pomyślnie.

Maglob, z miłości do bardziej praktycznej strony rzeczy, masz to wszystko najlepiej. @ Thorbjørn, myślę, że Maglob podążał bardziej wzdłuż linii, że jeśli twój projekt jest do bani, twoje testy z pewnością będą musiały bezpośrednio podciągnąć do poziomu sirności, którą próbujesz zmaterializować, a zepsuty zapach powinien śmierdzieć w twoich testach przed zaczynasz nawet pisać dowolny kod.
Filip Dupanović

3

Podejście „test pisemny + refaktor do zaliczenia” wygląda niesamowicie antyinżynieryjnie.

Wygląda na to, że masz błędne przekonanie dotyczące zarówno refaktoryzacji, jak i TDD.

Refaktoryzacja kodu to proces zmiany kodu źródłowego programu komputerowego bez modyfikowania jego zewnętrznego zachowania funkcjonalnego w celu poprawy niektórych niefunkcjonalnych atrybutów oprogramowania.

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.


Nie sądzę, że mam błędne przekonanie; Zgadzam się z definicją refaktoryzacji kodu, którą opublikowałeś, ale uważam również, że musisz przyjrzeć się szczegółowości zmian w kodzie. Kiedy mówisz „proces zmiany kodu źródłowego programu komputerowego”, musisz zdać sobie sprawę, że z perspektywy pewnej całości zachowanie się nie zmienia, ale zachowanie części rzeczywiście się zmienia. W ten sposób dokonuje się zmiana. Poza tym słyszę o tym, dlaczego TDD działa (i udostępniam to), ale w jaki sposób adresowana jest architektura zgodnie z moim oryginalnym postem?
CesarGon

@CesarGon: Post został zaktualizowany.
back2dos

2

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.


Słyszę o korzyściach, o które wnioskujesz w związku z TDD. Ale o ile rozumiem, nie rozwiązujesz problemów architektury i jakości testów, o które wyraźnie pytam w moim pytaniu.
CesarGon 30.01.11

@CesarGon: Myślę, że twoje szczegółowe pytania dotyczą każdego rodzaju testów, nie tylko TDD. Właśnie skupiłem się na konkretnych funkcjach TDD, które „działają”.
sevenseacat

1
Testy integracyjne zdecydowanie mają większy sens niż samodzielne testy jednostkowe. Większość przypadków błędów, na które natknęłam się, nigdy nie zostałaby wykryta podczas testów jednostkowych, tylko poprzez przetestowanie całego prawdziwego systemu ze wszystkimi jego śrubami i gwizdkami na miejscu.

2

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


+1 za dobre wyjaśnienie mojego pierwszego punktu i odniesienie do Hanka Moody'ego. Wspaniały.
CesarGon

2
Dzięki doceniam to. Uważam TDD bardziej za zjawisko psychologiczne niż za podejście techniczne / proces. Ale to tylko mój pogląd na świat w tej sprawie.
Filip Dupanović

Czy wiesz dokładnie, ile toalet i gdzie powinny być umieszczone? Odpowiedź brzmi: tak - zapytaj dowolnego architekta, a powiedzą ci, że informacje te są tworzone z góry, a czasem z jasnymi danymi statystycznymi na ich poparcie.
gbjbaanb

1

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


Nie zgadzam się z twoją implikacją, że w fizycznych (tj. Nie programowych) systemach odtworzenie awarii jest łatwe. Spójrz na przykład na niezwykle złożoną, ciężką pracę, która jest konieczna do ustalenia podstawowych przyczyn awarii mechanicznych w wypadkach drogowych.
CesarGon 30.01.11

Hm, teraz porównujesz rozbijający się Airliner z zawodzącym mostem, most zwykle nie może latać, skrzynia zamknięta. Ale porównanie samolotów i oprogramowania jest czasem prawidłowe. Oba obszary są bardzo złożone i wymagają ustrukturyzowanej metodologii testów. Więc kiedy most zawiedzie, wiesz, że został przeciążony. Kiedy samolot ulega awarii, dobrze wiesz, że nie powiódł się nienormalny stan lotu nad ziemią, ale zwykle powód wymaga dokładnego zbadania tego samego w przypadku awarii oprogramowania.
Ernelli,

Mosty mogą być powielane - a przynajmniej projekt mostu kupionego od architekta może, z grubsza, z modyfikacjami dostosowanymi do konkretnych okoliczności. Chodzi o to, że jeśli potrzebujesz mostu, pójdziesz do architekta, a on da ci listę tylko kilku rodzajów, które możesz mieć - zawieszenie, skrzynię, łuk itp., A także ograniczoną listę materiałów, z których można go zbudować.
gbjbaanb

1

Jeśli zaakceptujesz, że im szybciej zostaną znalezione błędy, tym mniejszy koszt ich naprawy, to samo to sprawia, że ​​TDD jest opłacalne.


1
Czy masz jakieś dowody na to, że błędy wykryto wcześniej w ustawieniach TDD? A co z efektami ubocznymi TDD, takimi jak wpływ na architekturę?
CesarGon 30.01.11

0

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.


6
-1. Wiele osób wciąż to mówi, ale jeszcze nie widziałem magii, która to powoduje.
Bart van Ingen Schenau

@Bart van Ingen Schenau, zrobiłeś TDD? Robię to od około 4 lat i zdecydowanie widziałem, jak się dzieje „magia”.
Marcie

0

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.


0

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.


0

Dlaczego działa TDD?

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.

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.