Jestem nowym programistą (uczę się tylko od około roku), a moim celem, aby być w tym lepszym, niedawno dowiedziałem się o TDD. Chciałem przyzwyczaić się do używania go, ponieważ wydaje się to bardzo pomocne. Chciałem to sprawdzić i upewnić się, że używam go poprawnie.
Co ja robię:
- Pomyśl o nowej metodzie, której potrzebuję.
- Utwórz test dla tej metody.
- Test negatywny.
- Napisz metodę.
- Zdać test.
- Metoda refaktoryzacji.
- Powtarzać.
Robię to dla KAŻDEJ metody, którą piszę, czy są jakieś, z którymi nie powinienem się przejmować? Później zwykle myślę o sposobie przetestowania moich już istniejących metod w inny sposób lub w innej sytuacji. Czy powinienem wykonać te nowe testy, o których myślę, czy skoro każda metoda ma już własny test, czy nie powinienem się tym przejmować? Czy mogę OVER testować mój kod? Myślę, że moim głównym problemem jest zadawanie tego pytania.
EDYTOWAĆ
Zastanawiałem się nad tym. Czy podczas tworzenia czegoś takiego jak GUI, TDD byłoby konieczne w takiej sytuacji? Osobiście nie mogę wymyślić, jak napisałbym na to testy.
Odpowiedzi:
To, co opisujesz jako przepływ pracy, nie jest moim zdaniem duchem TDD.
Streszczenie książki Kent Becks na Amazon mówi:
Praktyczny TDD
Formalne zautomatyzowane testowanie, zwłaszcza testowanie jednostkowe, każda metoda każdej klasy jest równie złym anty-wzorcem i niczego nie testuje. Należy zachować równowagę. Czy piszesz testy jednostkowe dla każdej
setXXX/getXXX
metody, one również są metodami!Testy mogą również pomóc zaoszczędzić czas i pieniądze, ale nie zapominaj, że ich opracowanie i opracowanie kosztuje dużo czasu i pieniędzy. Są one kodem, więc utrzymują czas i pieniądze. Jeśli zanikną z powodu braku utrzymania, stają się zobowiązaniem bardziej niż korzyścią.
Podobnie jak wszystko inne, istnieje równowaga, której nikt inny nie może zdefiniować. Wszelkie dogmaty w obu kierunkach są prawdopodobnie bardziej błędne niż poprawne.
Dobrą miarą jest kod, który ma kluczowe znaczenie dla logiki biznesowej i podlega częstym modyfikacjom w zależności od zmieniających się wymagań. Te rzeczy wymagają zautomatyzowanych testów formalnych, które byłyby dużym zwrotem z inwestycji.
Będziesz bardzo ciężko znaleźć wiele profesjonalnych sklepów, które działają w ten sposób. Po prostu nie ma sensu wydawanie pieniędzy na testowanie rzeczy, które we wszystkich praktycznych celach nigdy się nie zmienią po wykonaniu prostego testu dymu. Pisanie formalnych automatycznych testów jednostkowych dla
.getXXX/.setXXX
metod jest doskonałym przykładem tego, kompletnego marnowania czasu.Zobacz także tę odpowiedź .
źródło
setXXX/getXXX
wcale nie jest potrzebna :)Jesteś bardzo blisko. Spróbuj myśleć w ten nieco inny sposób.
Nie twórz automatycznie obiektów pobierających i ustawiających dla każdej właściwości . Nie myśl o całej metodzie i napisz test (y), które obejmą całą funkcjonalność . Spróbuj obudować właściwości wewnątrz klasy i napisz metody, aby zapewnić potrzebne zachowanie. Pozwól, aby twoje metody ewoluowały w dobry projekt, zamiast próbować je planować z góry. Pamiętaj, że TDD to proces projektowania, a nie proces testowania. Przewaga nad innymi procesami projektowymi polega na pozostawieniu za sobą strumienia automatycznych testów regresji, a nie na kawałku papieru, który wrzucasz do kosza.
Pamiętaj też o trzech zasadach TDD wuja Boba .
źródło
Kilka rzeczy do dodania do odpowiedzi innych:
Istnieje coś takiego jak nadmierne testowanie. Chcesz mieć pewność, że testy jednostkowe nakładają się na siebie w jak najmniejszym stopniu. Nie ma sensu, aby wiele testów weryfikowało te same warunki w tym samym fragmencie kodu. Z drugiej strony, gdy refaktoryzujesz kod produkcyjny i masz wiele testów pokrywających się z tą sekcją, będziesz musiał wrócić i naprawić wszystkie te testy. Natomiast jeśli się nie pokrywają, to jedna zmiana najwyżej przerwie tylko jeden test.
Tylko dlatego, że pomyślałeś o lepszym sposobie napisania testu, nie wrócę tam i nie zacznę go przepisywać. To wraca do osób, które wciąż piszą i przepisują tę samą klasę / funkcję, ponieważ starają się ją doskonalić. To nigdy nie będzie idealne, więc idź dalej. Kiedy odkryjesz lepszą metodę, nie zapominaj o niej (lub dodaj komentarz do testu). Następnym razem, gdy tam będziesz, i zobaczysz natychmiastową korzyść z przejścia na nowy sposób, nadszedł czas na refaktoryzację. W przeciwnym razie, jeśli funkcja jest gotowa, a ty przeszedłeś dalej i wszystko działa, zostaw ją działającą.
TDD koncentruje się na zapewnieniu natychmiastowej wartości, a nie po prostu upewnieniu się, że każda funkcja jest testowalna. Po dodaniu funkcjonalności zacznij od pytania „czego potrzebuje klient”. Następnie zdefiniuj interfejs, aby dać klientowi to, czego potrzebuje. Następnie zaimplementuj wszystko, co potrzebne do zdania testu. TDD jest prawie jak testowanie scenariuszy przypadków użycia (w tym wszystkich „co-jeśli”), a nie po prostu kodowanie funkcji publicznych i testowanie każdego z nich.
Zapytałeś o testowanie kodu GUI. Wyszukaj wzorce „Humble Dialog” i „MVVM”. Ideą obu tych metod jest utworzenie zestawu klas „modelu widoku”, które w rzeczywistości nie mają logiki specyficznej dla interfejsu użytkownika. Jednak klasy te będą miały całą logikę biznesową, która zazwyczaj stanowi część interfejsu użytkownika, i klasy te powinny być w 100% testowalne. To, co zostało, to bardzo cienka powłoka interfejsu użytkownika i tak, zwykle ta powłoka pozostaje bez pokrycia testowego, ale w tym momencie nie powinna mieć prawie żadnej logiki.
Jeśli masz dużą część istniejącego kodu, jak sugerowało niewiele innych, nie powinieneś zaczynać dodawać testów jednostkowych absolutnie wszędzie. Zajmie ci to wieczność i nie odniesiesz korzyści z dodania testów jednostkowych do 80% klas, które są stabilne i nie zmienią się w bliskiej (lub nie tak bliskiej) przyszłości. Jednak w przypadku nowej pracy uważam, że używanie programowania TDD z WSZYSTKIM kodem jest niezwykle korzystne. Po zakończeniu nie tylko otrzymujesz pakiet z automatycznymi testami, ale faktyczny rozwój ma ogromne zalety:
źródło
Istnieje kilka metod, które nie są testowane, a mianowicie te testy. Jest jednak coś, co można powiedzieć o niektórych testach dodawanych po napisaniu kodu początkowego, takich jak warunki brzegowe i inne wartości, aby możliwe było przeprowadzenie wielu testów na jednej metodzie.
Chociaż możesz nadmiernie przetestować swój kod, zwykle przychodzi to tam, gdzie ktoś chce przetestować każdą możliwą kombinację danych wejściowych, co nie brzmi jak to, co robisz. Na przykład, jeśli masz metodę, która przyjmuje znak, czy piszesz test dla każdej możliwej wartości, którą można wprowadzić? To byłby moment, w którym można by przeprowadzić nadmierny test, IMO.
źródło
Ogólnie robisz to dobrze.
Testy są kodem. Więc jeśli możesz ulepszyć test, śmiało go przerób. Jeśli uważasz, że test można ulepszyć, przejdź dalej i zmień go. Nie bój się zastąpić testu lepszym.
Zalecam podczas testowania kodu unikaj określania, w jaki sposób kod ma robić to, co robi. Testy powinny sprawdzać wyniki metod. Pomoże to w refaktoryzacji. Niektóre metody nie muszą być jawnie testowane (np. Proste metody pobierające i ustawiające), ponieważ użyjesz ich do weryfikacji wyników innych testów.
źródło
Moja opinia na temat TDD jest taka, że narzędzia stworzyły świat programistów w stylu „wskaż i kliknij”. To, że narzędzia tworzą odcinek testowy dla każdej metody, nie oznacza, że powinieneś pisać testy dla każdej metody. Niektóre osoby „zmieniają nazwę” TDD na BDD (programowanie oparte na zachowaniu), gdzie testy są o wiele bardziej szczegółowe i mają na celu przetestowanie zachowania klasy, a nie każda skomplikowana metoda.
Jeśli projektujesz swoje testy do testowania klasy zgodnie z przeznaczeniem, zaczniesz czerpać pewne korzyści, zwłaszcza gdy zaczniesz pisać testy, które wykonują nieco więcej niż każdą metodę, zwłaszcza gdy zaczniesz testować interakcję tych metody Podejrzewam, że można by pomyśleć o pisaniu testów dla klasy, a nie metod. W każdym razie nadal musisz napisać „testy akceptacyjne”, które sprawdzają kombinację metod, aby upewnić się, że nie ma sprzeczności ani konfliktów w ich wspólnym stosowaniu.
Nie myl TDD z testowaniem - nie jest. TDD jest zaprojektowane tak, abyś pisał kod, aby wykonać swoje wymagania, a nie testować metody. Jest to subtelna, ale ważna kwestia, często tracona przez osoby, które ślepo piszą kod testowy dla każdej metody. Powinieneś pisać testy, które upewniają się, że kod robi to, co chcesz, a nie, że napisany kod działa tak, jak powinien.
Istnieje kilka dobrych linków po prawej stronie na temat BDD v TDD. Sprawdź je.
źródło
Kiedy zaczniesz uczyć się TDD, tak, powinieneś ślepo postępować zgodnie z dogmatycznym podejściem, aby nie pisać ani jednego wiersza kodu, z wyjątkiem zaliczenia testu zakończonego niepowodzeniem, i napisania tylko tyle testu, aby się nie powiódł .
Gdy dowiesz się, o co chodzi w TDD, NASTĘPNIE możesz zdecydować, że pewne rzeczy nie są warte testowania. To jest to samo podejście, które powinieneś stosować do wszystkiego, a japońskie sztuki walki nazywają to „ shuhari ”. (Link wyjaśnia również, w jaki sposób można przejść przez etapy uczenia się bez nauczyciela, co jest, jak podejrzewam, sposobem, w jaki większość ludzi musi się uczyć).
źródło
Uważam, że przesadzasz.
Ćwiczę TDD od wielu lat i z mojego doświadczenia wynika, że kiedy TDD jest wykonywane skutecznie, zyskujesz dwie główne korzyści:
Szybka informacja zwrotna
Szczególnie w przypadku języków dynamicznych mogę wykonać odpowiednie testy w mniej niż sekundę. Mam obserwatorów systemu plików, którzy automatycznie uruchamiają te testy po zmianie pliku źródłowego na dysku. Dlatego praktycznie nie mam czasu na testy i od razu wiem, czy kod, który piszę, działał zgodnie z oczekiwaniami. Zatem TDD prowadzi do bardzo wydajnego sposobu pracy.
Włącz refaktoryzację
Jeśli masz dobry zestaw testów, możesz bezpiecznie refaktoryzować, ponieważ zyskujesz nowy wgląd w to, jak system powinien zostać zaprojektowany.
Dobry pakiet testowy pozwala przenieść odpowiedzialność w kodzie i mieć pewność, że kod będzie działał zgodnie z oczekiwaniami po przeniesieniu. I powinieneś być w stanie to zrobić przy niewielkich zmianach w kodzie testowym.
Jeśli napiszesz testy dla każdej metody w twoim systemie, istnieje prawdopodobieństwo, że nie możesz łatwo refaktoryzować kodu, każdy refaktor twojego kodu będzie wymagał ogromnych zmian w kodzie testowym. Czy możesz być pewien, że kod testowy nadal działa zgodnie z oczekiwaniami? A może przypadkowo wprowadziłeś błąd w kodzie testowym, co w konsekwencji prowadzi do błędu w kodzie produkcyjnym?
Jeśli jednak, jak sugeruje odpowiedź pdr , podczas pisania testów skupisz się na zachowaniu zamiast metod , będziesz mieć testy, które będą wymagały znacznie mniej zmian podczas refaktoryzacji systemu.
Lub, jak mówi Ian Cooper w tej prezentacji (cytowałem z pamięci, więc może być niepoprawnie cytowany):
źródło
Powinieneś przetestować każdą publiczność metodę.
Problem polega na tym, że jeśli twoje metody publiczne są bardzo małe, prawdopodobnie ujawniasz zbyt wiele informacji. Powszechną praktyką eksponowania każdej nieruchomości jako
getXXX()
faktycznie przerywa enkapsulację.Jeśli twoje metody publiczne są zachowaniem klasy, powinieneś je przetestować. Jeśli nie, nie są to dobre publiczne metody.
EDYCJA: odpowiedź pdr jest znacznie bardziej kompletna niż moja.
źródło