Dlaczego nie napisać wszystkich testów na raz podczas wykonywania TDD?


54

Cykl Czerwonego - Zielonego - Refaktora dla TDD jest dobrze ustalony i zaakceptowany. Piszemy jeden nieudany test jednostkowy i sprawiamy, że przechodzi on tak prosto, jak to możliwe. Jakie są korzyści z tego podejścia w porównaniu z pisaniem wielu nieudanych testów jednostkowych dla klasy i sprawianiem, że wszystkie przejdą za jednym razem.

Pakiet testowy nadal chroni Cię przed pisaniem niepoprawnego kodu lub popełnianiem błędów na etapie refaktoryzacji, więc jaka szkoda? Czasami łatwiej jest najpierw napisać wszystkie testy dla klasy (lub modułu) jako formę „zrzutu mózgu”, aby szybko zapisać wszystkie oczekiwane zachowanie za jednym razem.


20
Zrób to, co dla ciebie najlepsze (po eksperymentach). Ślepe podążanie za dogmatem nigdy nie jest dobrą rzeczą.
Michael Borgwardt,

6
Śmiem twierdzić, że pisanie wszystkich testów naraz przypomina pisanie całego kodu aplikacji na raz.
Michael Haren

1
@MichaelHaren Wszystkie testy dla klasy (lub modułu funkcjonalnego), przepraszam za zamieszanie
RichK

3
Rozwiązanie problemu „zrzutu mózgu”: Czasami istnieją punkty w testowaniu / kodowaniu, gdy zdajesz sobie sprawę z potrzeby kilku różnych konkretnych testów wejściowych, i istnieje tendencja, aby chcieć wykorzystać jasność tej realizacji, zanim rozproszysz się z drobiazgi kodowania. Zwykle radzę sobie z tym, utrzymując osobną listę (np. Mylyn) lub listę komentarzy w klasie Test różnych rzeczy, które chcę pamiętać, aby przetestować (np. // test null case). Jednak wciąż koduję tylko jeden test na raz i zamiast tego systematycznie schodzę w dół listy.
Sam Goldberg,

1
cóż, nie wiem, dlaczego nikt o tym nie wspominał, ale NIE MOŻESZ napisać wszystkich testów na raz. Pisanie wszystkich testów przed rozdaniem jest dokładnie takie samo jak wykonywanie BDUF . A czego nauczyła nas historia o BDUF? To prawie nigdy nie działa.
Songo,

Odpowiedzi:


49

Projekt oparty na testach dotyczy poprawnego działania interfejsu API , a nie kodu.

Zaletą napisania najprostszych testów zakończonych niepowodzeniem jest to, że otrzymujesz API (które zasadniczo projektujesz w locie) tak prosto, jak to możliwe. Z przodu.

Wszelkie przyszłe zastosowania (które są następnymi testami, które napiszesz) przejdą od początkowego prostego projektu, zamiast nieoptymalnego projektu, radzącego sobie z bardziej złożonymi przypadkami.


Doskonałe punkty! Czasami jesteśmy tak zanurzeni w testowaniu kodu, że czasami ignorujemy, jak ważny może być interfejs API i model domeny, nawet przed napisaniem pierwszego testu.
wałek klonowy

+1 za faktyczne zajęcie się intencją rozwoju opartego na testach .
Joshua Drake

76

Kiedy piszesz jeden test, koncentrujesz się na jednej rzeczy.
Dzięki wielu testom koncentrujesz się na wielu zadaniach, więc nie jest to dobry pomysł.


8
Kto by to głosował ?!
CaffGeek,

6
@Chad nie byłem zagłosowany, ale wierzę, że ta odpowiedź jest oczywista. Programowanie oparte na testach polega na wykorzystaniu testów do kierowania projektem kodu. Test pisze się indywidualnie, aby ewoluować projekt, a nie tylko testowalność. Gdyby chodziło tylko o artefakty testowe, byłaby to dobra odpowiedź, ale brakuje w niej pewnych istotnych informacji.
Joshua Drake

7
Nie głosowałem za tym, ale; Myślałem o tym. To zdecydowanie zbyt krótka odpowiedź na złożone pytanie.
Mark Weston,

2
+1 za koncentrację na jednej rzeczy na raz, nasza zdolność do wielozadaniowości jest przereklamowana.
cctan

To najprostsza odpowiedź, która może zadziałać.
DNA

26

Jedną z trudności podczas pisania testów jednostkowych jest to, że piszesz kod, a to samo w sobie może potencjalnie być podatne na błędy. Istnieje również możliwość, że będziesz musiał później zmienić swoje testy w wyniku refaktoryzacji podczas pisania kodu implementacyjnego. Dzięki TDD oznacza to, że potencjalnie możesz trochę za bardzo dać się ponieść testom i odkryć, że musisz przepisać wiele zasadniczo „niesprawdzonego” kodu testowego, gdy twoja implementacja dojrzewa w trakcie projektu. Jednym ze sposobów uniknięcia tego rodzaju problemu jest po prostu skupienie się na robieniu jednej rzeczy naraz. Dzięki temu zminimalizujesz wpływ wszelkich zmian na twoje testy.

Oczywiście w dużej mierze sprowadza się to do sposobu pisania kodu testowego. Czy piszesz test jednostkowy dla każdej metody, czy piszesz testy, które koncentrują się na cechach / wymaganiach / zachowaniach? Innym podejściem może być zastosowanie podejścia opartego na zachowaniu z odpowiednią strukturą i skoncentrowanie się na pisaniu testów, jakby były specyfikacjami. Oznaczałoby to albo przyjęcie metody BDD, albo dostosowanie testów BDD, jeśli chcesz trzymać się TDD w bardziej formalny sposób. Alternatywnie możesz całkowicie trzymać się paradygmatu TDD, ale zmienić sposób pisania testów, aby zamiast skupiać się wyłącznie na metodach testowania indywidualnie, testujesz zachowania bardziej ogólnie jako sposób na spełnienie specyfiki wymagań, które wdrażasz.

Niezależnie od tego, jakie podejście podejmiesz, we wszystkich przypadkach, które opisałem powyżej, używasz podejścia polegającego na pierwszym przetestowaniu, więc chociaż może być kuszące, aby po prostu pobrać swój mózg do pięknego zestawu testów, chcesz również walczyć pokusa, by zrobić więcej niż to absolutnie konieczne. Ilekroć mam rozpocząć nowy pakiet testowy, zaczynam powtarzać sobie YAGNI, a czasem nawet wrzucam go do komentarza w moim kodzie, aby przypomnieć mi, żebym skupił się na tym, co jest natychmiastowo ważne i robił tylko minimum wymagane do spełnienia wymagania funkcji, którą zamierzam wdrożyć. Trzymanie się Refaktora Czerwono-Zielonego pomaga zapewnić, że to zrobisz.


Cieszę się, że zwrócił Pan uwagę na różnicę między sposobem pisania kodu testowego. Niektórzy lubią pisać test pojedynczego urządzenia głównego, który obejmuje każdą realistyczną możliwość wprowadzenia danych wejściowych do jednej funkcji lub metody. Inni stosują podejście bardziej BDD w swoich testach jednostkowych. To rozróżnienie jest ważne przy ustalaniu, czy napisanie całego zestawu testów jest ważne, jest koniecznie złą praktyką, czy nie. Świetny wgląd!
wałek klonowy

17

Myślę, że robiąc to, przegapisz proces TDD. Po prostu pisząc wszystkie testy na początku, tak naprawdę nie przechodzisz przez proces opracowywania za pomocą TDD. Po prostu zgadujesz, które testy będą potrzebne. Będzie to zupełnie inny zestaw testów niż te, które kończysz pisaniem, jeśli wykonujesz je pojedynczo podczas opracowywania kodu. (Chyba że twój program będzie trywialny z natury).


1
Większość aplikacji biznesowych i korporacyjnych ma z technicznego punktu widzenia trywialny charakter, a ponieważ większość aplikacji ma charakter biznesowy i korporacyjny, większość aplikacji jest z natury trywialna.
wałek klonowy

5
@maple_shaft - technologia może być trywialna, ale reguły biznesowe nie są. Spróbuj zbudować aplikację dla 5 menedżerów, którzy mają różne wymagania i nie chcą słuchać trochę BS o twoim prostym, eleganckim, minimalistycznym designie.
JeffO,

5
@JeffO 1) To nie jest BS. 2) Elegancki minimalistyczny design wymaga dobrych umiejętności programistycznych. 3) Zdolność do złagodzenia wymagań 5 różnych menedżerów, którzy nie mają więcej niż 5 minut tygodniowo, aby zmarnować się z tobą i nadal realizować minimalistyczny projekt, wymaga doskonałego programisty. Wskazówka: Rozwój oprogramowania to coś więcej niż tylko umiejętności kodowania, to negocjacje, rozmowy i przejęcie własności. Musisz być psem Alpha i czasami gryźć.
wałek klonowy

1
Jeśli dobrze rozumiem, ta odpowiedź nasuwa pytanie.
Konrad Rudolph

1
@maple_shaft Myślę, że właśnie o to Jeff O miał do czynienia ze swoim komentarzem, nie?
ZweiBlumen

10

„Piszę” wszystkie testy, które mogę sobie wyobrazić podczas „burzy mózgów”, ale piszę każdy test jako pojedynczy komentarz opisujący test.

Następnie przekonwertowałem jeden test na kod i wykonałem pracę, aby się skompilował i zdał . Często decyduję się, że nie potrzebuję wszystkich testów, które tak myślałem, lub potrzebuję różnych testów, ta informacja pochodzi tylko z pisania kodu, aby testy przebiegły pomyślnie.

Problem polega na tym, że nie możesz napisać testu w kodzie, dopóki nie utworzysz metody i klas, które testuje, ponieważ w przeciwnym razie dostaniesz wiele błędów kompilatora, które przeszkadzają w pracy nad jednym testem naraz.

Teraz, jeśli używasz systemu przypominającego specyfikację, gdy testy są napisane w języku angielskim, możesz poprosić klientów o zgodę na zestaw testów, kiedy masz na to czas, zamiast tworzyć tylko jeden test.


1
Tak, zgadzając się z powyższymi odpowiedziami, które wskazują problemy z kodowaniem wszystkich twoich testów jako pierwsze, uważam, że bardzo pomocne jest porzucenie mojej ogólnej wiedzy o tym, jak powinna zachowywać się bieżąca metoda jako zestaw opisów testów bez żadnego kodu. Proces ich zapisywania ma tendencję do wyjaśniania, czy całkowicie rozumiem, czego wymaga kod, który zamierzam napisać, i czy są przypadki skrajne, o których nie myślałem. Czuję się o wiele wygodniej kodować pierwszy test, a potem go zdać, gdy nakreślę „przegląd” sposobu, w jaki metoda powinna działać.
Mark Weston

10

Ideą TDD są szybkie iteracje.

Jeśli masz dużą liczbę testów, które należy napisać przed napisaniem kodu, trudno jest iteracyjnie refaktoryzować kod.

Bez łatwego refaktoryzacji kodu tracisz wiele zalet TDD.


5

W moim (ograniczonym) doświadczeniu z TDD mogę powiedzieć, że za każdym razem, gdy łamałem dyscyplinę pisania jednego testu na raz, sprawy szły źle. Łatwo wpaść w pułapkę. „Och, ta metoda jest trywialna” - myślisz - więc po prostu powalę te dwa inne powiązane testy i ruszam dalej ”. Zastanów się? Nic nie jest tak trywialne, jak się wydaje. Za każdym razem, gdy wpadałem w tę pułapkę, debugowałem coś, co wydawało mi się łatwe, ale okazało się, że mam dziwne narożne skrzynki. A ponieważ napisałem kilka testów jednocześnie, ustalenie, gdzie był błąd, było bardzo ciężkie.

Jeśli potrzebujesz zrzutu informacji, masz wiele opcji:

  • Biała tablica
  • Historie użytkownika
  • Komentarze
  • Dobry stary długopis i papier

Zauważ, że nigdzie na tej liście nie ma kompilatora. :-)


5

Zakładasz, że wiesz, jak będzie wyglądał Twój kod, zanim go napiszesz. TDD / BDD jest zarówno procesem projektowania / odkrywania, jak i procesem zapewniania jakości. Dla danej funkcji piszesz najprostszy test, który sprawdzi, czy dana funkcja jest spełniona (czasami może to wymagać kilku z powodu złożoności funkcji). Pierwszy test, który piszesz, jest obciążony założeniami, jak będzie wyglądał działający kod. Jeśli napiszesz cały pakiet testowy przed napisaniem pierwszego wiersza kodu, który go obsługuje, robisz litanię niezweryfikowanych założeń. Zamiast tego napisz jedno założenie i zweryfikuj je. Następnie napisz następny. Podczas weryfikacji następnego założenia możesz po prostu złamać wcześniejsze założenie, więc musisz wrócić i zmienić to pierwsze założenie, aby dopasować je do rzeczywistości lub zmienić rzeczywistość, aby pierwsze założenie nadal obowiązywało.

Pomyśl o każdym teście jednostkowym, który piszesz, jako teorii w zeszycie naukowym. Wypełniając notatnik, dowodzisz swoich teorii i tworzysz nowe. Czasami udowodnienie, że nowa teoria obala poprzednią teorię, więc musisz ją naprawić. Łatwiej jest udowodnić jedną teorię naraz niż próbować udowodnić powiedzmy 20 naraz.


TDD zakłada, że ​​wiesz, jak będzie wyglądać Twój kod, zanim go napiszesz, tylko w mniejszych częściach.
Michael Shaw

4

TDD to wysoce iteracyjne podejście, które (z mojego doświadczenia) lepiej pasuje do rzeczywistych sposobów rozwoju. Zazwyczaj moja implementacja kształtuje się stopniowo podczas tego procesu, a każdy krok może przynieść dalsze pytania, spostrzeżenia i pomysły na testowanie. Jest to idealne rozwiązanie, aby skoncentrować się na rzeczywistym zadaniu i jest bardzo wydajne, ponieważ muszę przechowywać ograniczoną liczbę rzeczy w pamięci krótkotrwałej w dowolnym momencie. To z kolei zmniejsza prawdopodobieństwo błędów.

Twój pomysł to w zasadzie podejście Big Test Up Front, z którym IMHO jest trudniejsze w obsłudze i może stać się bardziej marnotrawstwem. Co się stanie, jeśli w połowie pracy zdasz sobie sprawę, że twoje podejście nie jest dobre, Twój interfejs API jest wadliwy i musisz zacząć wszystko od nowa lub zamiast tego użyć biblioteki innej firmy? Potem wiele pracy włożonej w pisanie testów z góry staje się zmarnowanym wysiłkiem.

To powiedziawszy, jeśli to zadziała, w porządku. Mogę sobie wyobrazić, że jeśli pracujesz na podstawie stałej, szczegółowej specyfikacji technicznej, w domenie, z którą masz bliskie doświadczenie i / lub przy dość małym zadaniu, możesz mieć większość lub wszystkie niezbędne przypadki testowe gotowe, a wdrażanie jasne od samego początku początek. Wtedy warto zacząć od napisania wszystkich testów na raz. Jeśli masz doświadczenie, że dzięki temu będziesz bardziej produktywny na dłuższą metę, nie musisz się zbytnio przejmować zasadami :-)


4

Oprócz myślenia tylko o jednej rzeczy, jednym z paradygmatów TDD jest napisanie możliwie najmniejszego kodu, aby przejść test. Kiedy piszesz jeden test na raz, o wiele łatwiej jest zobaczyć ścieżkę do napisania wystarczającej ilości kodu, aby ten test mógł zostać zaliczony. Z całym zestawem testów do przejścia, nie przychodzisz do kodu małymi krokami, ale musisz zrobić duży skok, aby wszystkie przebiegły za jednym razem.

Teraz, jeśli nie ograniczysz się do pisania kodu, aby wszyscy przeszli „za jednym razem”, ale raczej piszesz tyle kodu, aby przejść jeden test na raz, może nadal działać. Musisz jednak zachować większą dyscyplinę, aby nie tylko pisać i pisać więcej kodu, niż potrzebujesz. Kiedy zaczniesz tę ścieżkę, pozostawiasz się otwarty na pisanie większej ilości kodu niż opisują testy, co można przetestować , przynajmniej w tym sensie, że nie jest on przeprowadzany przez test i być może w tym sensie, że nie jest potrzebny (lub wykonane) przez dowolny test.

Zrozumienie, co powinna zrobić metoda, takie jak komentarze, historie, specyfikacja funkcjonalna itp., Jest całkowicie dopuszczalne. Chciałbym jednak przełożyć je na testy pojedynczo.

Inną rzeczą, której możesz pominąć, pisząc testy naraz, jest proces myślenia, dzięki któremu zdanie testu może skłonić Cię do myślenia o innych przypadkach testowych. Bez zestawu istniejących testów należy pomyśleć o kolejnym przypadku testowym w kontekście ostatniego testu pozytywnego. Jak już powiedziałem, dobre wyobrażenie o tym, co ma zrobić metoda, jest bardzo dobre, ale wiele razy znalazłem nowe możliwości, których nie rozważałem a priori, ale które pojawiły się tylko w trakcie pisania testy. Istnieje niebezpieczeństwo, że możesz je przegapić, chyba że przyzwyczaisz się myśleć, jakie nowe testy mogę napisać, których jeszcze nie mam.


3

Pracowałem nad projektem, w którym programiści, którzy napisali (nieudane) testy, różnili się od programistów wdrażających niezbędny kod, aby je przejść, i stwierdziłem, że jest on naprawdę skuteczny.

W takim przypadku tylko testy związane z bieżącą iteracją zostały napisane jeden raz. To, co sugerujesz, jest całkowicie możliwe w tego rodzaju scenariuszu.


2
  • Następnie próbujesz skoncentrować się na zbyt wielu rzeczach jednocześnie.
  • Podczas wdrażania, aby wszystkie testy przeszły pomyślnie, nie masz działającej wersji aplikacji. Jeśli musisz dużo wdrożyć, przez długi czas nie będziesz mieć działającej wersji.

2

Cykl Red-Green-Refactor to lista kontrolna przeznaczona dla deweloperów, którzy nie znają TDD. Powiedziałbym, że dobrze jest postępować zgodnie z tą listą kontrolną, dopóki nie wiesz, kiedy i kiedy możesz ją złamać (to znaczy, dopóki nie wiesz, że nie musisz zadawać tego pytania podczas stackoverflow :)

Po ukończeniu TDD przez prawie dekadę mogę powiedzieć, że bardzo rzadko, jeśli w ogóle, piszę wiele nieudanych testów przed napisaniem kodu produkcyjnego.


1

Opisujesz BDD, gdzie jakiś zewnętrzny interesariusz ma wykonywalną specyfikację. Może to być korzystne, jeśli istnieje z góry określona specyfikacja (na przykład specyfikacja formatu, standard przemysłowy lub gdy programista nie jest ekspertem w dziedzinie).

Normalnym podejściem jest wówczas stopniowe obejmowanie coraz większej liczby testów akceptacyjnych, co jest postępem widocznym dla kierownika projektu i klienta.

Zazwyczaj testy te są określone i wykonywane w ramach BDD, takich jak Cucumber, Fitnesse lub niektóre podobne.

Nie jest to jednak coś, co mieszasz z testami jednostkowymi, które są znacznie bliższe szczegółowym szczegółom implementacji z wieloma przypadkowymi krawędziami związanymi z API, problemami z inicjalizacją itp. Silnie skoncentrowanymi na testowanym elemencie , który jest artefaktem implementacji .

Dyscyplina czerwono-zielonego refaktora ma wiele zalet, a jedyną zaletą, na którą możesz liczyć, wpisując je z góry, jest osiągnięcie progu rentowności.


1

Jeden test na raz: główną zaletą jest skupienie się na jednej rzeczy. Pomyśl o projektowaniu w pierwszej kolejności: możesz wejść głęboko i pozostać skupionym dzięki pętli szybkiego sprzężenia zwrotnego. Możesz jednak pominąć zakres całego problemu! Właśnie w tym momencie wchodzi w grę (duża) refaktoryzacja. Bez niego TDD nie działa.

Wszystkie testy: analiza i projektowanie mogą ujawnić więcej zakresu problemu. Pomyśl o pierwszym projekcie. Analizujesz problem pod wieloma kątami i dodajesz doświadczenia. Jest to z natury trudniejsze, ale może przynieść ciekawe korzyści - mniej refaktoryzacji - jeśli zrobisz to „wystarczająco dużo”. Strzeż się, że łatwo jest przesadzić z analizą, a mimo to całkowicie nie trafić.

Trudno mi ogólnie zalecić wybranie jednego lub drugiego, ponieważ czynników jest wiele: doświadczenie (szczególnie z tym samym problemem), wiedza i umiejętności w dziedzinie, łatwość kodowania do refaktoryzacji, złożoność problemu ...

Sądzę, że jeśli skupimy się bardziej na typowych aplikacjach biznesowych, wówczas TDD z podejściem polegającym na szybkim prawie próbach i błędach zwykle wygrywa pod względem skuteczności.


1

Zakładając, że twoja platforma testowa to obsługuje, sugerowałbym, że zamiast implementować testy, które chcesz braindump, zamiast tego napisz opisowe testy oczekujące, które później zaimplementujesz. Na przykład, jeśli twój interfejs API powinien wykonywać foo i bar, ale nie biz, po prostu dodaj następujący kod (ten przykład jest w rspec) do swojego zestawu testów, a następnie atakuj je jeden po drugim. Szybko myślisz i możesz rozwiązać wszystkie swoje problemy jeden po drugim. Po przejściu wszystkich testów dowiesz się, kiedy rozwiązałeś wszystkie problemy, które miałeś podczas braindumpa.

describe "Your API" do

  it "should foo" do
    pending "braindump from 4/2"
  end

  it "should bar" do
    pending "braindump from 4/2"
  end

  it "should not biz" do
    pending "braindump from 4/2"
  end

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