Czy testy rozwoju testowego (TDD) są zawsze testami jednostkowymi?

41

Rozumiem do tej pory rozwój oparty na testach, że możesz pisać produktywny kod tylko wtedy, gdy masz nieudany (czerwony) test jednostkowy. Na tej podstawie mam pytanie, czy podejście oparte na testach można również zastosować do innych form testów.

użytkownik1364368
źródło
6
Często zdarza się, że używa się więcej niż jednego innego poziomu czerwonego / zielonego / refaktora zagnieżdżonego w sobie. Na przykład możesz śledzić czerwony / zielony / refaktor podczas pisania testów akceptacji / zachowania, gdzie „zielona” faza samego testu akceptacji zawiera wiele iteracji testów jednostkowych w kolorze czerwonym / zielonym / refaktorze.
Sean Burton,
1
Tytuł nie pasuje do treści pytania. Tytuł „testy zawsze są testami jednostkowymi ” (odpowiedź: nie, mogą istnieć inne typy testów niż testy jednostkowe), treść pyta „czy najpierw musisz napisać test?”.
AnoE
@AnoE Pierwsze zdanie treści to tylko wprowadzenie. Drugie zdanie nie pyta, czy test musi być napisany jako pierwszy, ale czy podejście TDD można zastosować do metod testowych innych niż TDD.
user1364368
@ user1364368, nie krępuj się przeformułować pytanie, przynajmniej byłem zdezorientowany co do twojej intencji podczas pierwszego czytania i pytania, na które najczęściej głosowano, a odpowiedź na oba zdania również zaczyna się od pierwszego.
AnoE,
@AnoE Zmieniłem początek drugiego zdania, aby wyjaśnić, jakie jest rzeczywiste pytanie.
user1364368

Odpowiedzi:

27

Wszystko, czego wymaga TDD, to napisanie testu zakończonego niepowodzeniem, a następnie zmodyfikowanie kodu, aby przejść pomyślnie.

Zazwyczaj „testy jednostkowe” są małe i szybkie i testują pewną część kodu osobno. Ponieważ są szybkie, dzięki temu pętla czerwona / zielona / reaktorowa również jest szybka. Jednak cierpią z powodu testowania tylko części w izolacji. Potrzebujesz więc także innych testów (integracja, akceptacja itp.). Nadal dobrą praktyką jest przestrzeganie tych samych zasad: napisz test zakończony niepowodzeniem, a następnie zmodyfikuj kod, aby działał. Pamiętaj tylko, że są one zwykle wolniejsze, więc mogą wpływać na czas cyklu czerwony / zielony / refaktor.

David Arno
źródło
59

Cykl refaktoryzacji w kolorze czerwonym i zielonym opiera się na jednej bardzo solidnej zasadzie:

Ufaj tylko testom, które widziałeś zarówno pozytywnie, jak i negatywnie.

Tak, działa to również z automatycznymi testami integracji. Również testy ręczne. Cholera, działa na testerach akumulatorów samochodowych. W ten sposób testujesz test.

Niektórzy myślą, że testy jednostkowe obejmują najmniejszą rzecz, którą można przetestować. Niektórzy myślą o wszystkim, co można szybko przetestować. TDD to coś więcej niż tylko czerwony zielony cykl refaktora, ale ta część ma bardzo specyficzny zestaw testów: to nie są testy, które najlepiej przeprowadzić raz przed przesłaniem zbioru zmian. To testy, które będziesz przeprowadzać za każdym razem, gdy dokonasz jakiejkolwiek zmiany. Dla mnie to są twoje testy jednostkowe.

candied_orange
źródło
1
Jest to również jeden z powodów, dla których testowanie negatywne jest ważne podczas testowania, czy wystąpił błąd: chcesz się upewnić, że wszystko inne działałoby, więc mając dwa testy (jeden produkujący dokładnie oczekiwany błąd, drugi nie generujący błędu) obok wzajemnie pomagają zwiększyć pewność, że w przyszłości ten stan czerwony / zielony będzie trwał.
Matthieu M.
12

Zastanawiam się jednak, czy podejście oparte na testach można również zastosować do innych form testów.

Tak, a dobrze znanym podejściem, które to robi, jest rozwój oparty na zachowaniu . Testy generowane na podstawie formalnej specyfikacji w BDD można nazwać „testami jednostkowymi”, ale zazwyczaj nie będą one tak niskie, jak w prawdziwym TDD, prawdopodobnie lepiej pasują do terminu „testy akceptacyjne”.

Doktor Brown
źródło
8

Rozumiem do tej pory rozwój oparty na testach, że możesz pisać produktywny kod tylko wtedy, gdy masz nieudany (czerwony) test jednostkowy.

Nie. Możesz napisać tylko najprostszy możliwy kod, aby zmienić komunikat testu. Nie mówi nic o tym, jaki rodzaj testu.

W rzeczywistości prawdopodobnie zaczniesz od napisania nieudanego (czerwonego) testu akceptacji dla kryterium akceptacji, a ściślej piszesz najprostszy test akceptacji, który może się nie powieść; następnie uruchom test, zobacz, jak się nie udaje, i sprawdź, czy nie powiedzie się z właściwego powodu. Następnie piszesz niepomyślny test funkcjonalny dla fragmentu funkcjonalności tego kryterium akceptacji, ponownie piszesz najprostszy test funkcjonalny, który może się nie powieść, uruchom go, obserwuj, jak się nie udaje i sprawdź, czy nie powiedzie się z właściwego powodu. Następnie piszesz nieudany test jednostkowy, najprostszy test jednostkowy, który może się nie powieść, uruchom go, obserwuj, jak się nie udaje, sprawdź, czy nie udaje się to z właściwego powodu.

Teraz piszesz najprostszy kod produkcyjny, który może zmienić komunikat o błędzie. Uruchom test ponownie, sprawdź, czy komunikat o błędzie zmienił się, czy zmienił właściwy kierunek i czy kod zmienił komunikat z właściwego powodu. (Idealnie, komunikat o błędzie powinien już zniknąć, a test powinien przejść pomyślnie, ale najczęściej lepiej jest zrobić małe kroki, zmieniając komunikat, niż próbować zmusić test do przejścia za jednym razem - to jest powód dlaczego programiści środowisk testowych tyle wysiłku poświęcają na komunikaty o błędach!)

Po przejściu testu jednostkowego refaktoryzujesz kod produkcyjny pod ochroną swoich testów. (Zauważ, że w tej chwili test akceptacyjny i test funkcjonalny nadal się nie udaje, ale to dobrze, ponieważ refaktoryzujesz tylko pojedyncze jednostki objęte testami jednostkowymi).

Teraz tworzysz następny test jednostkowy i powtarzasz powyższe, aż test funkcjonalny również przejdzie. Pod ochroną testu funkcjonalnego możesz teraz refaktoryzować wiele jednostek.

Ten środkowy cykl powtarza się teraz, aż przejdzie test akceptacji, w którym to momencie można teraz dokonać refaktoryzacji w całym systemie.

Teraz wybierasz kolejne kryterium akceptacji i cykl zewnętrzny zaczyna się od nowa.

Kent Beck, „odkrywca” TDD (nie lubi terminu „wynalazca”, mówi, że ludzie to robią przez cały czas, po prostu nadał mu nazwę i napisał o tym książkę) używa analogii z fotografii i nazywa to „powiększaniem i pomniejszaniem”.

Uwaga: nie zawsze potrzebujesz trzech poziomów testów. Może czasem potrzebujesz więcej. Częściej potrzebujesz mniej. Jeśli twoje funkcje są małe, a testy funkcjonalne są szybkie, możesz sobie poradzić bez (lub z mniejszą liczbą testów jednostkowych). Często potrzebujesz tylko testów akceptacyjnych i testów jednostkowych. Lub kryteria akceptacji są tak szczegółowe, że testy akceptacyjne testami funkcjonalnymi.

Kent Beck mówi, że jeśli ma szybki, mały i skoncentrowany test funkcjonalny, najpierw napisze testy jednostkowe, pozwoli testom jednostkowym przeprowadzić kod, a następnie ponownie usunie (niektóre) testy jednostkowe obejmujące kod, który również jest kodem objęty szybkim testem funkcjonalnym. Pamiętaj: kod testowy to także kod, który należy utrzymywać i refaktoryzować, im mniej, tym lepiej!

Zastanawiam się jednak, czy podejście oparte na testach można również zastosować do innych form testów.

Tak naprawdę nie stosuje się TDD do testów. Stosujesz go do całego procesu programowania. To, co „napędzany” część test- Driven -Rozwój środki: wszystko twój rozwój jest napędzany za pomocą testów. Testy nie tylko napędzać kod piszesz, też jeżdżą co kod pisać, co pisać następny kod. Oni napędzają twój projekt. Mówią ci, kiedy skończysz. Mówią ci, nad czym dalej pracować. Informują o wadach projektowych w kodzie (gdy testy są trudne do napisania).

Keith Braithwaite stworzył ćwiczenie, które nazywa TDD tak, jakbyś to rozumiał . Składa się z zestawu zasad (opartych na trzech regułach TDD wuja Boba Martina , ale o wiele surowszych), których należy ściśle przestrzegać i które mają na celu bardziej rygorystyczne stosowanie TDD. Działa najlepiej z programowaniem par (aby twoja para mogła upewnić się, że nie łamiesz zasad) i instruktorem.

Reguły są następujące:

  1. Napisz dokładnie jeden nowy test, najmniejszy test, jaki możesz wskazać w kierunku rozwiązania
  2. Zobacz, jak zawodzi; niepowodzenia kompilacji liczą się jako awarie
  3. Wykonaj test z (1), pisząc najmniejszy możliwy kod implementacyjny w metodzie testowej .
  4. Przeprowadź refaktoryzację, aby usunąć duplikację, i w inny sposób, aby poprawić projekt. Bądź ostrożny przy użyciu tych ruchów:
    1. chcesz nowej metody - poczekaj do czasu refaktoryzacji, a następnie… utwórz nowe (nietestowe) metody, wykonując jedną z tych czynności i w żaden inny sposób:
      • preferowane: wykonaj Wyodrębnij metodę z kodu implementacji utworzonego zgodnie z (3), aby utworzyć nową metodę w klasie testowej, lub
      • jeśli musisz: przenieść kod implementacji zgodnie z (3) do istniejącej metody implementacji
    2. chcesz nowej klasy - poczekaj do czasu refaktoryzacji, a następnie… utwórz klasy nietestowe, aby zapewnić miejsce docelowe dla metody przenoszenia bez żadnego innego powodu
    3. wypełniaj klasy implementacyjne metodami, wykonując metodę Move, i nie ma innej możliwości

Te zasady są przeznaczone do wykonywania TDD. Nie są przeznaczone do robienia TDD w produkcji (chociaż nic nie powstrzymuje cię przed wypróbowaniem). Mogą czuć się frustrujące, ponieważ czasami wydaje się, że wykonujesz tysiące drobnych małych kroków bez żadnego rzeczywistego postępu.

Jörg W Mittag
źródło
2

TDD wcale nie ogranicza się do tego, co tradycyjna społeczność testowania oprogramowania nazywa „testowaniem jednostkowym”. To bardzo powszechne nieporozumienie jest wynikiem niefortunnego przeciążenia przez Kenta Becka terminu „jednostka”, kiedy opisywał swoją praktykę TDD. Co miał na myśli przez „test jednostkowy” to test, który działa w izolacji. Nie zależy to od innych testów. Każdy test musi skonfigurować wymagany stan i wykonać wszelkie czyszczenie po zakończeniu. W tym sensie test jednostkowy w sensie TDD jest jednostką. Jest samodzielny. Może działać samodzielnie lub może być uruchamiany z dowolnym innym testem jednostkowym w dowolnej kolejności.

Odniesienie : „Test Driven Development By Przykład”, autor: Kent Beck

Kent Beck opisuje, co rozumie przez „test jednostkowy” w rozdziale 32 - Opanowanie TDD

Jason Desrosiers
źródło
1

Nie czytałem na ten temat książek ani nie przestrzegam całkowicie „standardowych” praktyk TDD, ale moim zdaniem głównym celem filozofii TDD, z którą się całkowicie zgadzam, jest to, że najpierw musisz zdefiniować sukces . Jest to ważne na każdym poziomie projektowania, od „Jaki jest cel tego projektu?” na „Jakie powinny być dane wejściowe i wyjściowe tej małej metody?”

Istnieje wiele sposobów realizacji tej definicji sukcesu. Przydatnym, szczególnie w przypadku metod niskiego poziomu z potencjalnie wieloma przypadkami brzegowymi, jest pisanie testów w kodzie. W przypadku niektórych poziomów abstrakcji przydatne może być napisanie krótkiej notatki na temat celu modułu lub czegoś innego, a nawet po prostu sprawdzenie siebie (lub poproszenie współpracownika), aby upewnić się, że wszystko ma sens i że ma sens logiczne miejsce. Czasami pomocne jest opisanie testu integracji w kodzie (i oczywiście pomaga to go zautomatyzować), a czasem pomocne jest zdefiniowanie rozsądnego planu szybkiego testu, którego można użyć, aby upewnić się, że wszystkie systemy działają razem tak, jak Ty oczekują.

Ale niezależnie od konkretnych technik lub narzędzi, których używasz, moim zdaniem kluczową rzeczą, aby odejść od filozofii TDD, jest to, że określenie sukcesu ma miejsce najpierw. W przeciwnym razie rzucasz strzałką, a następnie malujesz dziesiątkę wszędzie tam, gdzie to się stało.


źródło
1

W rozmowie Test-Driven Development: Nie o to nam chodziło. Steve Freeman pokazuje następujący slajd dużego obrazu TDD (patrz zdjęcie poniżej odpowiedzi). Obejmuje to krok „Napisz nieudany test kompleksowy”, a następnie „Napisz nieudany test jednostkowy”. (Kliknij, aby powiększyć, w prawym górnym rogu)

Więc nie w TDD testy nie zawsze są testami jednostkowymi.

I tak, możesz (a może powinieneś) zacząć od testu kompleksowego wyższego poziomu, który kończy się niepowodzeniem, zanim napiszesz pierwszy test jednostkowy. Ten test opisuje zachowanie, które chcesz osiągnąć. Generuje to zasięg na większej liczbie piramid testowych . Adrian Sutton wyjaśnia doświadczenie LMAX, które pokazuje, że kompleksowe testy mogą odegrać dużą i cenną rolę .

wprowadź opis zdjęcia tutaj

Niels van Reijmersdal
źródło
-1

Nie, nie można go zastosować do innego rodzaju testów z prostego praktycznego powodu: wykonywanie innych rodzajów testów trwa zbyt długo.

Typowy cykl TDD to: test nieudanego zapisu, implementacja, kod refaktora. Kolejne kroki to budowanie i przeprowadzanie testów, które muszą być błyskawiczne. Jeśli nie są, ludzie zaczną pomijać kroki, a wtedy nie będziesz już robić TDD.

BЈовић
źródło
1
Jest to niepoprawne: w zależności od programu i testu (i języka) kompleksowe testy integracyjne można łatwo uruchomić w mniej niż 3 sekundy. Całkowicie możliwe jest uruchomienie pełnego zestawu testów w bardzo krótkim czasie, nawet jeśli jest dobrze zaprojektowany. Więc „nie mogę” jest dość silny.
Jonathan Cast
@jcast Nigdy nie widziałem czegoś tak szybkiego. Moje testy funkcjonalne mojego poprzedniego projektu trwały 30 sekund i to jest szybkie. Integracja jeszcze dłużej. W moim przypadku nic innego nie miało sensu. Ponadto testy jednostkowe są najszybsze ze wszystkich rodzajów testów - dlatego warto z nich korzystać.
BЈовић