Co stracę, przyjmując projektowanie testowe?
Wymień tylko negatywy; nie wymieniaj świadczeń napisanych w formie negatywnej.
Co stracę, przyjmując projektowanie testowe?
Wymień tylko negatywy; nie wymieniaj świadczeń napisanych w formie negatywnej.
Odpowiedzi:
Kilka wad (i nie twierdzę, że nie ma żadnych korzyści - szczególnie przy pisaniu podstaw projektu - na koniec zaoszczędziłoby to dużo czasu):
Jeśli chcesz wykonać „rzeczywistą” TDD (czytaj: najpierw przetestuj za pomocą czerwonych, zielonych, refaktoryzujących kroków), musisz także zacząć używać makiet / kodów pośredniczących, gdy chcesz przetestować punkty integracji.
Kiedy zaczniesz używać prób, po chwili będziesz chciał zacząć używać Dependency Injection (DI) i kontenera Inversion of Control (IoC). Aby to zrobić, musisz używać interfejsów do wszystkiego (które same mają wiele pułapek).
Pod koniec dnia musisz napisać o wiele więcej kodu, niż gdybyś zrobił to po prostu „po prostu starą drogą”. Zamiast tylko klasy klienta, musisz także napisać interfejs, próbną klasę, trochę konfiguracji IoC i kilka testów.
I pamiętaj, że kod testowy powinien być również utrzymywany i pielęgnowany. Testy powinny być tak czytelne jak wszystko inne i napisanie dobrego kodu zajmuje dużo czasu.
Wielu programistów nie do końca rozumie, jak zrobić to wszystko „we właściwy sposób”. Ale ponieważ wszyscy mówią im, że TDD jest jedynym prawdziwym sposobem na tworzenie oprogramowania, po prostu starają się jak mogą.
Jest to o wiele trudniejsze niż mogłoby się wydawać. Często projekty wykonane przy użyciu TDD kończą się kodem, którego nikt tak naprawdę nie rozumie. Testy jednostkowe często sprawdzają niewłaściwy sposób. I nikt nie zgadza się, jak powinien wyglądać dobry test, nawet tak zwani guru.
Wszystkie te testy znacznie utrudniają „zmianę” (w przeciwieństwie do refaktoryzacji) zachowania systemu, a proste zmiany stają się zbyt trudne i czasochłonne.
Jeśli czytasz literaturę TDD, zawsze znajdziesz kilka bardzo dobrych przykładów, ale często w rzeczywistych aplikacjach musisz mieć interfejs użytkownika i bazę danych. Tutaj TDD staje się naprawdę trudne, a większość źródeł nie oferuje dobrych odpowiedzi. A jeśli tak, zawsze wymaga to więcej abstrakcji: próbnych obiektów, programowania interfejsu, wzorców MVC / MVP itp., Które znów wymagają dużej wiedzy i ... musisz napisać jeszcze więcej kodu.
Więc bądź ostrożny ... jeśli nie masz entuzjastycznego zespołu i przynajmniej jednego doświadczonego programisty, który umie pisać dobre testy, a także wie kilka rzeczy o dobrej architekturze, naprawdę musisz pomyśleć dwa razy, zanim zejdziesz drogą TDD .
Gdy dojdziesz do miejsca, w którym masz dużą liczbę testów, zmiana systemu może wymagać ponownego napisania niektórych lub wszystkich testów, w zależności od tego, które zostały unieważnione przez zmiany. Może to zmienić stosunkowo szybką modyfikację w bardzo czasochłonną.
Ponadto możesz zacząć podejmować decyzje projektowe bardziej w oparciu o TDD niż w rzeczywistości dobrych projektantów. Chociaż mogłeś mieć bardzo proste i łatwe rozwiązanie, które nie jest w stanie przetestować wymagań TDD, masz teraz znacznie bardziej złożony system, który jest bardziej podatny na błędy.
if part of the system is covered by tests and they pass, then everything is fine (including design)
.
Myślę, że największym problemem jest dla mnie OGROMNA strata czasu potrzebna na „wejście w to”. Nadal jestem bardzo na początku mojej podróży z TDD (zobacz mój blog, aby uzyskać informacje o moich testowych przygodach, jeśli jesteś zainteresowany) i dosłownie spędziłem godziny na rozpoczęciu.
Przejście twojego mózgu w „tryb testowania” zajmuje dużo czasu, a pisanie „testowalnego kodu” jest umiejętnością samą w sobie.
TBH, z szacunkiem nie zgadzam się z komentarzami Jasona Cohena dotyczącymi upublicznienia prywatnych metod, nie o to chodzi. W moim nowym sposobie pracy nie uczyniłem więcej metod publicznych niż wcześniej . Wiąże się to jednak ze zmianami architektonicznymi i pozwala na „podłączenie” modułów kodu, aby wszystko inne było łatwiejsze do przetestowania. W tym celu nie powinieneś zwiększać dostępności wewnętrznych elementów kodu. W przeciwnym razie wracamy do punktu wyjścia, gdy wszystko jest publiczne, gdzie jest w tym enkapsulacja?
Tak więc (IMO) w skrócie:
PS: Jeśli chcesz uzyskać linki do pozytywów, zadałem i odpowiedziałem na kilka pytań na ten temat, sprawdź mój profil .
W ciągu kilku lat, w których ćwiczę Test Driven Development, muszę powiedzieć, że największe wady to:
TDD najlepiej wykonywać parami. Po pierwsze, trudno oprzeć się pokusie, aby po prostu napisać implementację, gdy WIESZ, jak napisać instrukcję if / else . Ale para sprawi, że wykonasz zadanie, ponieważ ty będziesz go wykonywać. Niestety wiele firm / menedżerów nie uważa, że jest to dobre wykorzystanie zasobów. Po co płacić, aby dwie osoby napisały jedną funkcję, skoro mam dwie funkcje, które należy wykonać w tym samym czasie?
Niektóre osoby po prostu nie mają cierpliwości do pisania testów jednostkowych. Niektórzy są bardzo dumni ze swojej pracy. Lub niektórzy po prostu widzą, jak zawiłe metody / funkcje spadają z końca ekranu. TDD nie jest dla wszystkich, ale naprawdę tego chciałbym. Ułatwiłoby to utrzymanie rzeczy tym biednym duszom, które odziedziczą kod.
Idealnie byłoby, gdyby testy zakończyły się niepowodzeniem tylko w przypadku podjęcia złej decyzji dotyczącej kodu. To znaczy, myślałeś, że system działał w jedną stronę i okazało się, że tak nie było. Przerwanie testu lub (małego) zestawu testów to właściwie dobra wiadomość. Wiesz dokładnie, jak twój nowy kod wpłynie na system. Jeśli jednak twoje testy są źle napisane, ściśle powiązane lub, co gorsza, wygenerowane ( test VS kaszel ), to utrzymanie testów może szybko stać się chórem. A gdy wystarczająca liczba testów zacznie powodować więcej pracy niż postrzegana wartość, którą tworzą, wówczas testy będą pierwszą rzeczą, która zostanie usunięta, gdy harmonogramy zostaną skompresowane (np. Dojdzie do awarii)
Idealnie, jeśli zastosujesz metodologię, twój kod zostanie domyślnie w 100% przetestowany. Zazwyczaj myślę, że kończę na pokryciu kodu w górę o 90%. Zwykle dzieje się tak, gdy mam architekturę stylu szablonu, a baza jest testowana, a ja próbuję wyciąć rogi, a nie przetestować dostosowania szablonu. Odkryłem również, że kiedy napotykam nową barierę, której wcześniej nie spotkałem, mam krzywą uczenia się podczas jej testowania. Przyznaję się do pisania niektórych wierszy kodu starym sposobem skool, ale naprawdę lubię mieć to w 100%. (Chyba skończyłem szkołę, er skool).
Powiedziałbym jednak, że korzyści wynikające z TDD znacznie przewyższają negatywy dla prostego pomysłu, że jeśli uda ci się uzyskać dobry zestaw testów obejmujących twoje zastosowanie, ale nie są tak delikatne, że jedna zmiana psuje je wszystkie, być w stanie dodawać nowe funkcje w dniu 300 projektu, tak jak w dniu 1. Nie dzieje się tak w przypadku wszystkich osób, które próbują TDD, uważając, że to magiczna kula dla całego ich błędnego kodu, więc myślą, że może to praca, kropka.
Osobiście przekonałem się, że dzięki TDD piszę prostszy kod, spędzam mniej czasu na debatowaniu, czy dane rozwiązanie kodu działa, czy nie, i nie boję się zmienić żadnej linii kodu, która nie spełnia kryteriów określonych przez drużyna.
TDD to trudna dyscyplina do opanowania, którą stosuję od kilku lat i wciąż uczę się nowych technik testowania. To z góry ogromna inwestycja czasowa, ale w dłuższej perspektywie trwałość będzie znacznie większa niż w przypadku braku automatycznych testów jednostkowych. Teraz, gdyby tylko moi szefowie potrafili to rozgryźć.
W twoim pierwszym projekcie TDD są dwie duże straty, czas i wolność osobista
Tracisz czas, ponieważ:
Tracisz wolność osobistą, ponieważ:
Mam nadzieję że to pomoże
TDD wymaga zaplanowania sposobu działania klas przed napisaniem kodu, który przejdzie te testy. Jest to zarówno plus, jak i minus.
Trudno mi pisać testy w „próżni” - przed napisaniem jakiegokolwiek kodu. Z mojego doświadczenia mam tendencję do potykania się o swoje testy, ilekroć nieuchronnie myślę o czymś podczas pisania moich zajęć, o których zapomniałem podczas pisania pierwszych testów. Potem nadszedł czas, aby nie tylko refaktoryzować moje zajęcia, ale także MOJE testy. Powtórz to trzy lub cztery razy i może to być frustrujące.
Wolę najpierw napisać szkic moich zajęć, a następnie napisać (i utrzymać) zestaw testów jednostkowych. Po otrzymaniu wersji roboczej TDD działa dla mnie dobrze. Na przykład, jeśli zgłoszony zostanie błąd, napiszę test, aby go wykorzystać, a następnie naprawię kod, aby test się powiódł.
Prototypowanie może być bardzo trudne z TDD - gdy nie jesteś pewien, jaką drogę zamierzasz rozwiązać, pisanie testów z góry może być trudne (inne niż bardzo szerokie). To może być ból.
Szczerze mówiąc, nie sądzę, aby w przypadku „podstawowego rozwoju” znacznej większości projektów istniały jakieś realne minusy; jest omawiany o wiele bardziej niż powinien, zwykle przez ludzi, którzy uważają, że ich kod jest wystarczająco dobry, aby nie potrzebowali testów (nigdy tak nie jest), a ludzie, którzy po prostu nie mogą zadać sobie trudu, aby je napisać.
Cóż, a to rozciąganie wymaga debugowania testów. Czas na napisanie testów wiąże się również z pewnym kosztem, choć większość ludzi zgadza się, że jest to inwestycja wstępna, która opłaca się przez cały okres użytkowania aplikacji zarówno w czasie oszczędzania czasu na debugowaniu, jak i stabilności.
Największym problemem, jaki osobiście z tym miałem jednak do czynienia, jest zebranie dyscypliny w pisaniu testów. W zespole, szczególnie w zespole o ustalonej pozycji, może być trudno przekonać ich, że spędzony czas jest opłacalny.
Jeśli twoje testy nie są bardzo dokładne, możesz wpaść w fałszywe poczucie „wszystko działa” tylko dlatego, że zdałeś testy. Teoretycznie, jeśli testy przejdą pomyślnie, kod działa; ale gdybyśmy mogli napisać kod idealnie za pierwszym razem, nie potrzebowalibyśmy testów. Morał polega na tym, aby samodzielnie sprawdzić poprawność psychiczną przed uznaniem czegoś za kompletne, nie polegaj tylko na testach.
W tej notatce, jeśli twój test poczytalności znajdzie coś, co nie jest testowane, koniecznie wróć i napisz test.
Wadą TDD jest to, że zwykle jest ściśle związane z metodologią „Agile”, która nie przywiązuje wagi do dokumentacji systemu, a raczej zrozumienie, dlaczego test „powinien” zwrócić jedną konkretną wartość, a nie jakąkolwiek inną rezyduje tylko w deweloperze głowa.
Gdy tylko programista opuści lub zapomni powód, dla którego test zwraca jedną konkretną wartość, a nie inną, jesteś wkręcony. TDD jest w porządku, JEŚLI jest odpowiednio udokumentowane i otoczone czytelną dla człowieka (tj. Pointy-managera) dokumentacją, do której można się odwołać za 5 lat, gdy zmieni się świat i twoja aplikacja również musi.
Kiedy mówię o dokumentacji, nie jest to nieporozumienie w kodzie, to jest oficjalne pismo, które istnieje poza aplikacją, takie jak przypadki użycia i informacje ogólne, do których mogą się odwołać menadżerowie, prawnicy i biedny sap, który musi zaktualizować twój kod w 2011 roku.
Spotkałem kilka sytuacji, w których TDD doprowadza mnie do szału. Aby wymienić niektóre:
Możliwość utrzymania przypadku testowego:
Jeśli jesteś w dużym przedsiębiorstwie, istnieje duża szansa, że nie musisz samodzielnie pisać przypadków testowych lub przynajmniej większość z nich została napisana przez kogoś innego, kiedy wchodzisz do firmy. Funkcje aplikacji zmieniają się od czasu do czasu, a jeśli nie masz zainstalowanego systemu, takiego jak HP Quality Center, do ich śledzenia, szybko oszalejesz.
Oznacza to również, że nowym członkom zespołu zajmie sporo czasu, aby zrozumieć, co się dzieje z przypadkami testowymi. To z kolei może przełożyć się na więcej potrzebnych pieniędzy.
Złożoność automatyzacji testów:
Jeśli zautomatyzujesz niektóre lub wszystkie przypadki testowe w skrypty testowe uruchamiane maszynowo, będziesz musiał upewnić się, że te skrypty testowe są zsynchronizowane z odpowiadającymi im ręcznymi testami i zgodne ze zmianami aplikacji.
Ponadto poświęcisz czas na debugowanie kodów, które pomogą Ci wykryć błędy. Moim zdaniem większość tych błędów wynika z tego, że zespół testujący nie odzwierciedlił zmian aplikacji w skrypcie testu automatyzacji. Zmiany w logice biznesowej, graficznym interfejsie użytkownika i innych wewnętrznych elementach mogą spowodować, że skrypty przestaną działać lub nie będą działać poprawnie. Czasami zmiany są bardzo subtelne i trudne do wykrycia. Kiedyś wszystkie moje skrypty zgłaszały awarię, ponieważ oparły swoje obliczenia na informacjach z tabeli 1, podczas gdy tabela 1 była teraz tabelą 2 (ponieważ ktoś zamienił nazwę obiektów tabeli w kodzie aplikacji).
Największym problemem są ludzie, którzy nie wiedzą, jak napisać odpowiednie testy jednostkowe. Piszą testy, które są od siebie zależne (i działają świetnie z Antem, ale potem nagle się nie udają, gdy uruchamiam je z Eclipse, tylko dlatego, że działają w innej kolejności). Piszą testy, które nie testują niczego konkretnego - po prostu debugują kod, sprawdzają wynik i zmieniają go w test, nazywając go „test1”. Rozszerzają zakres klas i metod tylko dlatego, że łatwiej będzie dla nich pisać testy jednostkowe. Kod testów jednostkowych jest okropny, ze wszystkimi klasycznymi problemami programistycznymi (ciężkie sprzęganie, metody o długości 500 linii, wartości zakodowane na stałe, powielanie kodu) i jest piekielnie trudny do utrzymania. Z jakiegoś dziwnego powodu ludzie traktują testy jednostkowe jako coś gorszego od „prawdziwego” kodu i nie w ogóle dbają o ich jakość. :-(
Tracisz dużo czasu na pisanie testów. Oczywiście można to zapisać do końca projektu, szybciej wychwytując błędy.
Największym minusem jest to, że jeśli naprawdę chcesz właściwie wykonywać TDD, będziesz musiał dużo zawieść, zanim odniesiesz sukces. Biorąc pod uwagę, ile firm produkujących oprogramowanie (dolar za KLOC) w końcu zostaniesz zwolniony. Nawet jeśli Twój kod jest szybszy, czystszy, łatwiejszy w utrzymaniu i zawiera mniej błędów.
Jeśli pracujesz w firmie, która płaci Ci przez KLOC (lub zaimplementowane wymagania - nawet jeśli nie zostały przetestowane), trzymaj się z dala od TDD (lub recenzji kodu, programowania w parach, ciągłej integracji itp. Itp.).
Tracisz możliwość stwierdzenia, że jesteś „skończony” przed przetestowaniem całego kodu.
Tracisz możliwość pisania setek lub tysięcy wierszy kodu przed jego uruchomieniem.
Tracisz możliwość uczenia się przez debugowanie.
Tracisz elastyczność wysyłania kodu, którego nie jesteś pewien.
Tracisz swobodę ścisłego łączenia modułów.
Tracisz opcję pomijania pisania dokumentacji projektowej niskiego poziomu.
Tracisz stabilność kodu, którą wszyscy boją się zmienić.
Popieram odpowiedź na temat początkowego czasu rozwoju. Tracisz także możliwość komfortowej pracy bez bezpieczeństwa testów. Zostałem też opisany jako głupek TDD, więc możesz stracić kilku przyjaciół;)
Ponowne skoncentrowanie się na trudnych, nieprzewidzianych wymaganiach jest stałą zmorą programisty. Rozwój oparty na testach zmusza Cię do skupienia się na znanych już, przyziemnych wymaganiach i ogranicza rozwój do tego, co już sobie wyobrażałeś.
Pomyśl o tym, prawdopodobnie skończysz na projektowaniu do konkretnych przypadków testowych, więc nie będziesz kreatywny i zaczniesz myśleć: „byłoby fajnie, gdyby użytkownik mógł zrobić X, Y i Z”. Dlatego gdy ten użytkownik zacznie się ekscytować potencjalnymi fajnymi wymaganiami X, Y i Z, Twój projekt może być zbyt sztywno skoncentrowany na już określonych przypadkach testowych i trudno będzie go dostosować.
To oczywiście miecz obosieczny. Jeśli poświęcisz cały swój czas na projektowanie każdego wyobrażalnego, możliwego do wyobrażenia, X, Y i Z, jakiego użytkownik może kiedykolwiek chcieć, nieuchronnie nigdy niczego nie ukończysz. Jeśli coś zrobisz, nikt (łącznie z tobą) nie będzie miał pojęcia, co robisz w kodzie / projekcie.
Pisanie testów „losowych” danych, takich jak kanały XML i bazy danych (może nie być trudne), może być trudne i czasochłonne. Ostatnio spędziłem trochę czasu, pracując z kanałami danych pogodowych. To dość mylące testy pisania, przynajmniej dlatego, że nie mam zbyt dużego doświadczenia z TDD.
Stracisz duże klasy z wieloma obowiązkami. Prawdopodobnie stracisz także duże metody z wieloma obowiązkami. Możesz stracić zdolność do refaktoryzacji, ale stracisz także część konieczności refaktoryzacji.
Jason Cohen powiedział coś w stylu: TDD wymaga pewnej organizacji twojego kodu. Może to być niepoprawne architektonicznie; na przykład, ponieważ metod prywatnych nie można wywoływać poza klasą, należy uczynić metody nieprywatnymi, aby można je było przetestować.
Mówię, że oznacza to pominięcie abstrakcji - jeśli kod prywatny naprawdę wymaga przetestowania, prawdopodobnie powinien być w osobnej klasie.
Dave Mann
Musisz pisać aplikacje w inny sposób: taki, który umożliwia ich testowanie. Byłbyś zaskoczony, jak trudne jest to na początku.
Niektórzy ludzie uważają, że myślenie o tym, co zamierzają napisać, zanim będą zbyt trudne. Pojęcia takie jak drwiny mogą być dla niektórych trudne. TDD w starszych aplikacjach może być bardzo trudne, jeśli nie zostały zaprojektowane do testowania. TDD wokół frameworków, które nie są przyjazne TDD, może być również walką.
TDD jest umiejętnością, więc młodsi deweloperzy mogą początkowo walczyć (głównie dlatego, że nie nauczono ich, aby działali w ten sposób).
Ogólnie rzecz biorąc, wady są rozwiązywane, gdy ludzie stają się wykwalifikowani, a ty w końcu wyodrębniasz „śmierdzący” kod i masz bardziej stabilny system.
Wszystkie dobre odpowiedzi. Dodałbym kilka sposobów na uniknięcie ciemnej strony TDD:
Napisałem aplikacje do zrobienia ich losowego autotestu. Problem z pisaniem konkretnych testów jest taki, że nawet jeśli piszesz ich dużo, dotyczą one tylko tych przypadków, o których myślisz. Generatory losowych testów znajdują problemy, o których nie pomyślałeś.
Cała koncepcja wielu testów jednostkowych sugeruje, że masz komponenty, które mogą dostać się do nieprawidłowych stanów, takie jak złożone struktury danych. Jeśli trzymasz się z dala od skomplikowanych struktur danych, jest o wiele mniej do przetestowania.
W zakresie, w jakim pozwala na to Twoja aplikacja, nie wstydź się projektu, który opiera się na właściwej kolejności powiadomień, zdarzeń i skutków ubocznych. Można je łatwo upuścić lub zakodować, więc wymagają wielu testów.
TDD wymaga pewnej organizacji dla twojego kodu. Może to być nieefektywne lub trudne do odczytania. Lub nawet architektonicznie niewłaściwy; na przykład, ponieważ private
metod nie można wywoływać poza klasą, należy uczynić metody nieprywatnymi, aby można je było przetestować, co jest po prostu błędne.
Kiedy kod się zmienia, musisz również zmienić testy. Przy refaktoryzacji może to być dużo dodatkowej pracy.
Dodam, że jeśli zastosujesz zasady BDD do projektu TDD, możesz złagodzić kilka głównych wad wymienionych tutaj (zamieszanie, nieporozumienia itp.). Jeśli nie znasz BDD, zapoznaj się ze wstępem Dana Northa. Wymyślił tę koncepcję w odpowiedzi na niektóre problemy wynikające z zastosowania TDD w miejscu pracy. Intro Dana do BDD można znaleźć tutaj .
Sugeruję tylko tę sugestię, ponieważ BDD rozwiązuje niektóre z tych negatywów i działa jak przerwa. Zastanów się nad tym, zbierając opinie.
Musisz upewnić się, że twoje testy są zawsze aktualne, moment, w którym zaczniesz ignorować czerwone światła, jest momentem, w którym testy stają się bez znaczenia.
Musisz także upewnić się, że testy są kompleksowe, lub w momencie pojawienia się dużego błędu, duszny typ zarządzania, który ostatecznie przekonałeś, abyś spędził czas na pisaniu większej ilości kodu, będzie narzekał.
Osoba, która nauczyła mojego zespołu zwinnego rozwoju, nie wierzyła w planowanie, napisałeś tyle samo dla najmniejszych wymagań.
Jego motto to: refaktor, refaktor, refaktor. Zrozumiałem, że refaktor oznacza „nie planować z wyprzedzeniem”.
Wydłuża się czas opracowywania: każda metoda wymaga przetestowania, a jeśli masz dużą aplikację z zależnościami, musisz przygotować i wyczyścić dane do testów.