Pierwotnie TDD wywodził się ze zwinnego ruchu, w którym testowanie zostało napisane z góry jako sposób na upewnienie się, że kodowanie pozostało poprawne, biorąc pod uwagę specyfikację, która została teraz dobrze zdefiniowana w kodzie testowym. Okazało się to również bardzo ważnym aspektem refaktoryzacji, ponieważ kiedy modyfikowałeś swój kod, możesz polegać na testach, aby udowodnić, że nie zmieniłeś zachowania kodu.
Potem pojawiły się narzędzia, które ludzie myśleli, że znają informacje o twoim kodzie, a następnie mogli wygenerować kody testowe, aby pomóc ci w pisaniu testów jednostkowych, i myślę, że tutaj wszystko poszło nie tak.
Kody testowe są generowane przez komputer, który nie ma pojęcia, co robisz, po prostu bezmyślnie tworzy kod pośredni dla każdej metody, ponieważ tak właśnie powinno być. Oznacza to, że masz przypadek testowy dla każdej metody, niezależnie od złożoności tej metody lub tego, czy nadaje się ona do testowania w izolacji.
Wynika to z testowania z niewłaściwego końca metodologii TDD. W TDD powinieneś dowiedzieć się, co ma zrobić kod, a następnie stworzyć kod, który to osiągnie. Jest to samospełniające się, ponieważ kończy się pisaniem testów, które dowodzą, że kod robi to, co robi, a nie to, co powinien. W połączeniu z automatycznym generowaniem kodów testowych opartych na metodach, marnujesz czas na udowadnianie każdego drobnego aspektu kodu, który może tak łatwo okazać się błędny, gdy wszystkie małe elementy zostaną złożone razem.
Kiedy Fowler opisał testowanie w swojej książce, odniósł się do testowania każdej klasy za pomocą własnej głównej metody. Udoskonalił to, ale koncepcja jest nadal taka sama - testujesz całą klasę, więc działa ona jako całość, wszystkie twoje testy są powiązane, aby udowodnić interakcję wszystkich tych metod, aby klasa mogła być ponownie użyta z określonymi oczekiwaniami.
Myślę, że zestawy narzędzi testowych zrobiły nam krzywdę, poprowadziły nas na ścieżkę myślenia, że zestaw narzędzi jest jedynym sposobem na robienie rzeczy, kiedy naprawdę musisz przemyśleć więcej, aby uzyskać najlepszy wynik z kodu. Ślepe umieszczanie kodu testowego w skrótach testowych dla drobnych elementów oznacza po prostu, że musisz powtórzyć swoją pracę w teście integracyjnym (a jeśli zamierzasz to zrobić, dlaczego nie pominąć całkowicie teraz nadmiarowego etapu testowania jednostek). Oznacza to również, że ludzie tracą dużo czasu na uzyskanie 100% pokrycia testowego, a także dużo czasu na tworzenie dużej ilości szydzącego kodu i danych, które lepiej byłoby spędzić, ułatwiając test integracji kodu (tj. Jeśli masz tak dużo zależności danych, test jednostkowy może nie być najlepszą opcją)
Wreszcie, kruchość testów jednostkowych opartych na metodzie po prostu pokazuje problem. Refaktoryzacja jest przeznaczona do użycia z testami jednostkowymi, jeśli twoje testy ciągle się psują, ponieważ refaktoryzujesz, to coś poszło poważnie nie tak z całym podejściem. Refaktoryzacja lubi tworzyć i usuwać metody, więc oczywiście podejście oparte na ślepej próbie na metodę nie jest pierwotnie zamierzone.
Nie mam wątpliwości, że wiele metod otrzyma dla nich testy, wszystkie publiczne metody klasy powinny zostać przetestowane, ale nie można oderwać się od koncepcji testowania ich razem w ramach jednego przypadku testowego. Na przykład, jeśli mam metodę set i get, mogę pisać testy, które wprowadzają dane i sprawdzają, czy elementy wewnętrzne są ustawione poprawnie, lub mogę użyć każdego z nich, aby wstawić jakieś dane, a następnie pobrać je ponownie, aby sprawdzić, czy jest to wciąż to samo i nie zniekształcone. To testuje klasę, a nie każdą metodę oddzielnie. Jeśli seter polega na prywatnej metodzie pomocnika, to jest w porządku - nie musisz kpić z prywatnej metody, aby upewnić się, że seter działa, nie jeśli przetestujesz całą klasę.
Wydaje mi się, że religia zajmuje się tym tematem, dlatego widzisz schizmę w tak zwanym rozwoju opartym na zachowaniu i testowaniu - pierwotna koncepcja testowania jednostkowego dotyczyła rozwoju opartego na zachowaniu.
Jak sama nazwa wskazuje, testujesz obiekt atomowy w każdym teście. Taki przedmiot jest zwykle pojedynczą metodą. Wiele testów może przetestować tę samą metodę, aby objąć szczęśliwą ścieżkę, możliwe błędy itp. Testujesz zachowanie, a nie mechanikę wewnętrzną. Testowanie jednostkowe polega zatem na testowaniu publicznego interfejsu klasy, czyli konkretnej metody.
W testach jednostkowych metodę należy przetestować w oderwaniu, tzn. Poprzez zubożenie / wyszydzenie / sfałszowanie dowolnych zależności. W przeciwnym razie testowanie jednostki z „rzeczywistymi” zależnościami czyni ją testem integracji. Jest czas i miejsce na oba typy testów. Testy jednostkowe zapewniają, że pojedynczy przedmiot działa zgodnie z oczekiwaniami, niezależnie. Testy integracyjne zapewniają, że „prawdziwe” podmioty działają razem poprawnie.
źródło
Moja ogólna zasada: najmniejsza jednostka kodu, która wciąż jest wystarczająco złożona, aby zawierać błędy.
Niezależnie od tego, czy jest to metoda, klasa czy podsystem, zależy od konkretnego kodu, nie można podać żadnej ogólnej reguły.
Na przykład nie zapewnia żadnej wartości do testowania prostych metod getter / setter w izolacji ani metod otoki, które wywołują tylko inną metodę. Nawet cała klasa może być zbyt prosta do przetestowania, jeśli klasa jest tylko cienkim opakowaniem lub adapterem. Jeśli jedyną rzeczą do przetestowania jest wywołanie metody na próbce, testowany kod jest cienki.
W innych przypadkach jedna metoda może wykonać skomplikowane obliczenia, które są cenne do przetestowania w izolacji.
W wielu przypadkach złożonymi częściami nie są poszczególne klasy, ale integracja między klasami. Więc testujesz dwie lub więcej klas jednocześnie. Niektórzy powiedzą, że nie są to testy jednostkowe, ale testy integracyjne, ale nie mówiąc o terminologii: powinieneś przetestować, gdzie jest złożoność, a testy te powinny być częścią zestawu testów.
źródło