Nasz kolega promuje pisanie testów jednostkowych jako faktycznie pomagających nam udoskonalić nasz projekt i refaktoryzować rzeczy, ale nie rozumiem, jak to zrobić. Jeśli ładuję plik CSV i analizuję go, w jaki sposób test jednostkowy (sprawdzanie poprawności wartości w polach) pomoże mi zweryfikować mój projekt? Wspomniał o sprzężeniu i modułowości itp., Ale dla mnie nie ma to większego sensu - ale nie mam zbyt dużego zaplecza teoretycznego.
To nie to samo, co pytanie, które zaznaczyłeś jako duplikat. Byłbym zainteresowany rzeczywistymi przykładami, w jaki sposób to pomaga, a nie tylko teorią mówiącą „pomaga”. Podoba mi się odpowiedź poniżej i komentarz, ale chciałbym dowiedzieć się więcej.
design
unit-testing
object-oriented-design
Użytkownik039402
źródło
źródło
Odpowiedzi:
Testy jednostkowe nie tylko ułatwiają projektowanie, ale jest to jedna z ich głównych zalet.
Napisanie pierwszego testu eliminuje modułowość i czystą strukturę kodu.
Kiedy piszesz swój kod w pierwszej kolejności, przekonasz się, że wszelkie „warunki” danej jednostki kodu są naturalnie wypychane do zależności (zwykle poprzez makiety lub kody pośredniczące), kiedy przyjmujesz je w swoim kodzie.
„Biorąc pod uwagę warunek x, spodziewaj się zachowania y”, często staje się odgałęzieniem do dostarczenia
x
(co jest scenariuszem, w którym test musi zweryfikować zachowanie bieżącego komponentu) iy
staje się próbą, której wywołanie zostanie zweryfikowane na koniec testu (chyba że jest to „powinien zwrócićy
”), w którym to przypadku test po prostu wyraźnie zweryfikuje zwracaną wartość).Następnie, gdy jednostka zachowuje się tak, jak określono, przechodzisz do pisania odkrytych zależności (dla
x
iy
).To sprawia, że pisanie czystego, modułowego kodu jest bardzo łatwym i naturalnym procesem, w przeciwnym razie często łatwo jest rozmazać obowiązki i powiązać zachowania bez uświadomienia sobie tego.
Pisząc testy później dowiesz się, kiedy twój kod ma słabą strukturę.
Kiedy pisanie testów dla fragmentu kodu staje się trudne, ponieważ jest zbyt wiele rzeczy do skartowania lub wyszydzenia, lub ponieważ rzeczy są zbyt ściśle ze sobą powiązane, wiesz, że masz ulepszenia w kodzie.
Kiedy „zmiana testów” staje się ciężarem, ponieważ w jednej jednostce jest tak wiele zachowań, wiesz, że masz ulepszenia w kodzie (lub po prostu w podejściu do pisania testów - ale z mojego doświadczenia nie jest tak zwykle) .
Gdy staje się zbyt skomplikowane scenariusze ( „jeśli
x
ay
, az
potem ...”), ponieważ trzeba bardziej abstrakcyjnego, wiesz, że masz ulepszenia wprowadzone w kodzie.Kiedy skończysz z tymi samymi testami w dwóch różnych urządzeniach ze względu na powielanie i redundancję, wiesz, że masz ulepszenia w kodzie.
Oto doskonała rozmowa Michaela Feathersa, pokazująca bardzo ścisły związek między testowalnością i projektowaniem w kodzie (pierwotnie opublikowana przez displayName w komentarzach). Rozmowa dotyczy również niektórych powszechnych skarg i nieporozumień na temat dobrego projektu i ogólnie testowalności.
źródło
Wspaniałą rzeczą w testach jednostkowych jest to, że pozwalają ci używać twojego kodu, tak jak inni programiści będą go używać.
Jeśli twój kod jest trudny do testowania jednostkowego, prawdopodobnie będzie trudny w użyciu. Jeśli nie możesz wstrzykiwać zależności bez przeskakiwania przez obręcze, prawdopodobnie kod będzie mało elastyczny w użyciu. A jeśli musisz poświęcić dużo czasu na konfigurowanie danych lub zastanawianie się nad kolejnością wykonywania zadań, testowany kod prawdopodobnie ma zbyt wiele sprzężeń i będzie trudny w pracy.
źródło
Zajęło mi to sporo czasu, ale prawdziwą korzyścią (edytuj: dla mnie twój przebieg może się różnić) z robienia testów opartych na testach ( przy użyciu testów jednostkowych) jest to, że musisz zaprojektować API z góry !
Typowe podejście do programowania polega na tym, aby najpierw dowiedzieć się, jak rozwiązać dany problem, a dzięki tej wiedzy i projektowi wstępnego wdrożenia można wywołać rozwiązanie. Może to dać dość interesujące wyniki.
Robiąc TDD, musisz jako pierwszy napisać kod, który użyje twojego rozwiązania. Parametry wejściowe i oczekiwane dane wyjściowe, aby upewnić się, że są prawidłowe. To z kolei wymaga, abyś zorientował się, co tak naprawdę musisz zrobić, abyś mógł tworzyć sensowne testy. Wtedy i tylko wtedy wdrażasz rozwiązanie. Z mojego doświadczenia wynika również, że kiedy dokładnie wiesz, co ma osiągnąć Twój kod, staje się on wyraźniejszy.
Następnie po wdrożeniu testy jednostkowe pomagają upewnić się, że refaktoryzacja nie psuje funkcjonalności, oraz dostarczają dokumentację na temat korzystania z kodu (który, jak wiesz, jest poprawny po zdaniu testu!). Ale są one drugorzędne - największą korzyścią jest sposób myślenia przy tworzeniu kodu.
źródło
Zgadzam się w 100%, że testy jednostkowe pomagają „pomóc nam udoskonalić nasz projekt i przefakturować rzeczy”.
Nie mam pojęcia, czy pomogą ci wykonać wstępny projekt . Tak, ujawniają oczywiste wady i zmuszają cię do zastanowienia się nad tym, „w jaki sposób mogę przetestować kod”? Powinno to prowadzić do mniejszej liczby skutków ubocznych, łatwiejszej konfiguracji i konfiguracji itp.
Jednak z mojego doświadczenia wynika, że zbyt uproszczone testy jednostkowe, napisane zanim naprawdę zrozumiesz, jaki powinien być projekt (co prawda, to przesada w przypadku twardego TDD, ale zbyt często koderzy piszą test, zanim dużo pomyślą) często prowadzą do anemii modele domen, które ujawniają zbyt wiele elementów wewnętrznych.
Moje doświadczenie z TDD było kilka lat temu, więc jestem zainteresowany usłyszeniem, jakie nowsze techniki mogą pomóc w pisaniu testów, które nie wpływają zbytnio na projekt podstawowy. Dzięki.
źródło
Test jednostkowy pozwala zobaczyć, jak działają interfejsy między funkcjami, i często daje wgląd w to, jak ulepszyć zarówno projekt lokalny, jak i projekt ogólny. Ponadto, jeśli rozwijasz testy jednostkowe podczas opracowywania kodu, masz gotowy pakiet testów regresji. Nie ma znaczenia, czy tworzysz interfejs użytkownika czy bibliotekę zaplecza.
Po opracowaniu programu (z testami jednostkowymi), gdy błędy zostaną wykryte, możesz dodać testy, aby potwierdzić, że błędy zostały usunięte.
Używam TDD do niektórych moich projektów. Włożyłem wiele wysiłku w tworzenie przykładów, które czerpię z podręczników lub artykułów uważanych za poprawne, i testuję kod, który rozwijam, korzystając z tych przykładów. Wszelkie nieporozumienia dotyczące metod stają się bardzo widoczne.
Zwykle jestem nieco luźniejszy niż niektórzy z moich kolegów, ponieważ nie dbam o to, czy kod jest napisany jako pierwszy, czy test jest napisany jako pierwszy.
źródło
Jeśli chcesz przetestować jednostkowo parser poprawnie wykrywający wartości rozdzielające, możesz chcieć przekazać jedną linię z pliku CSV. Aby twój test był bezpośredni i krótki, możesz przetestować go jedną metodą, która akceptuje jedną linię.
Spowoduje to automatyczne oddzielenie odczytu linii od odczytu poszczególnych wartości.
Na innym poziomie możesz nie chcieć umieszczać różnego rodzaju fizycznych plików CSV w swoim projekcie testowym, ale zrobić coś bardziej czytelnego, po prostu deklarując duży ciąg CSV w teście, aby poprawić czytelność i cel testu. Doprowadzi cię to do oddzielenia twojego parsera od dowolnego wejścia / wyjścia, które zrobiłbyś gdzie indziej.
Tylko prosty przykład, po prostu zacznij go ćwiczyć, w pewnym momencie poczujesz magię (mam).
źródło
Mówiąc prościej, pisanie testów jednostkowych pomaga ujawnić wady w kodzie.
Ten spektakularny przewodnik po pisaniu testowalnego kodu , napisany przez Jonathana Woltera, Russa Ruffera i Miško Hevery'ego, zawiera liczne przykłady tego, jak wady kodu, które blokują testowanie, również uniemożliwiają łatwe ponowne użycie i elastyczność tego samego kodu. Dlatego jeśli kod można przetestować, jest łatwiejszy w użyciu. Większość „moralności” to absurdalnie proste wskazówki, które znacznie poprawiają projektowanie kodu ( Dependency Injection FTW).
Na przykład: bardzo trudno jest przetestować, czy metoda computeStuff działa poprawnie, gdy pamięć podręczna rozpoczyna eksmisję. Jest tak, ponieważ musisz ręcznie dodać crap do pamięci podręcznej, aż „bigCache” będzie prawie pełny.
Jednak gdy używamy wstrzykiwania zależności, o wiele łatwiej jest sprawdzić, czy metoda computeStuff działa poprawnie, gdy pamięć podręczna zaczyna eksmitować rzeczy. Wszystko, co robimy, to stworzyć test, w którym nazywamy
new HereIUseDI(buildSmallCache());
Powiadomienie, mamy bardziej szczegółową kontrolę nad obiektem i natychmiast wypłaca dywidendy.Podobne korzyści można uzyskać, gdy nasz kod wymaga danych, które zwykle są przechowywane w bazie danych ... wystarczy przekazać DOKŁADNIE potrzebne dane.
źródło
W zależności od tego, co rozumie się przez „testy jednostkowe”, nie sądzę, aby naprawdę testy jednostkowe na niskim poziomie ułatwiały dobry projekt, podobnie jak testy integracji na nieco wyższym poziomie - testy, które sprawdzają, czy grupa aktorów (klasy, funkcje, cokolwiek) w Twój kod łączy się prawidłowo, aby stworzyć całą masę pożądanych zachowań, które zostały uzgodnione między zespołem programistycznym a właścicielem produktu.
Jeśli umiesz pisać testy na tych poziomach, popycha cię to do stworzenia ładnego, logicznego kodu podobnego do API, który nie wymaga wielu zwariowanych zależności - chęć posiadania prostej konfiguracji testu naturalnie doprowadzi cię do braku dużej ilości szalone zależności lub ściśle powiązany kod.
Nie popełnij jednak błędu - testy jednostkowe mogą prowadzić do złego projektu, a także dobrego projektu. Widziałem, jak programiści biorą trochę kodu, który ma już ładny logiczny projekt i jedną kwestię, i rozbijają go na części i wprowadzają więcej interfejsów wyłącznie w celu testowania, w wyniku czego kod jest mniej czytelny i trudniejszy do zmiany , a może nawet więcej błędów, jeśli deweloper zdecydował, że wiele testów jednostkowych na niskim poziomie oznacza, że nie muszą mieć testów wyższego poziomu. Szczególnym ulubionym przykładem jest naprawiony przeze mnie błąd, w którym było wiele bardzo zepsutego, „testowalnego” kodu związanego z uzyskiwaniem informacji ze schowka i poza nim. Wszystko podzielone i oddzielone do bardzo małych poziomów szczegółowości, z wieloma interfejsami, mnóstwem próbnych testów i innymi zabawnymi rzeczami. Tylko jeden problem - nie było żadnego kodu, który faktycznie wchodziłby w interakcję z mechanizmem schowka systemu operacyjnego,
Testy jednostkowe mogą zdecydowanie wpłynąć na twój projekt - ale nie prowadzą automatycznie do dobrego projektu. Musisz mieć pomysły na to, co to dobry projekt, który wykracza poza „ten kod jest testowany, dlatego jest testowalny, a więc dobry”.
Oczywiście, jeśli jesteś jedną z tych osób, dla których „testy jednostkowe” oznaczają „wszelkie testy automatyczne, które nie są przeprowadzane przez interfejs użytkownika”, niektóre z tych ostrzeżeń mogą nie być tak istotne - jak powiedziałem, myślę, że te wyższe -poziomowe testy integracyjne są często bardziej przydatne, jeśli chodzi o kierowanie projektem.
źródło
Testy jednostkowe mogą pomóc w refaktoryzacji, gdy nowy kod przejdzie wszystkie stare testy.
Załóżmy, że wdrożyłeś opcję bąbelków, ponieważ spieszyło ci się i nie martwiłeś wydajnością, ale teraz potrzebujesz szybkiego sortowania, ponieważ dane stają się coraz dłuższe. Jeśli wszystkie testy przejdą pomyślnie, wszystko wygląda dobrze.
Oczywiście testy muszą być kompleksowe, aby to zadziałało. W moim przykładzie twoje testy mogą nie obejmować stabilności, ponieważ nie było to przedmiotem zainteresowania z bąbelkami.
źródło
Odkryłem, że testy jednostkowe są najbardziej cenne dla ułatwienia długoterminowego utrzymania projektu. Kiedy po miesiącach wracam do projektu i nie pamiętam zbyt wielu szczegółów, przeprowadzanie testów powstrzymuje mnie od zepsucia rzeczy.
źródło