Jak przetestować testy?

53

Testujemy nasz kod, aby był bardziej poprawny (a właściwie mniej prawdopodobny ). Jednak testy są również kodem - mogą również zawierać błędy. A jeśli twoje testy są błędne, prawie nie poprawiają kodu.

Mogę wymyślić trzy możliwe typy błędów w testach:

  1. Błędy logiczne, gdy programista źle zrozumiał dane zadanie, a testy wykonują to, co według niego powinny zrobić, co jest złe;

  2. Błędy w podstawowych ramach testowych (np. Nieszczelna abstrakcja kpiąca);

  3. Błędy w testach: test robi się nieco inaczej niż myśli programista.

Błędy typu (1) wydają się niemożliwe do uniknięcia (chyba że programista po prostu ... stanie się mądrzejszy). Jednak (2) i (3) mogą być podatne na przełożenie. Jak radzisz sobie z tego rodzaju błędami? Czy masz jakieś specjalne strategie, aby ich uniknąć? Na przykład, czy piszesz jakieś specjalne „puste” testy, które sprawdzają tylko założenia autora testu? Jak podejść do debugowania uszkodzonego przypadku testowego?

Ryszard Szopa
źródło
3
Każdy wstępny artykuł, który przeczytałem o kpinach, wydaje się mieć ten problem. Gdy zaczniesz kpić z rzeczy, testy zawsze wydają się bardziej skomplikowane niż kod, który testują. Oczywiście jest to mniej prawdopodobne podczas testowania kodu w świecie rzeczywistym, ale jest to dość przygnębiające, gdy próbujesz się uczyć.
Carson63000,
@ Carson63000 Jeśli jest to proste testowanie testy coś z testowanym mock, złożoność jest podzielony i pod kontrolą (, myślę).
mlvljr,
13
Ale w jaki sposób testujesz testy testowe?
ocodo
+1. Pozycja 1 może być błędem wymagań. Można temu zapobiec jedynie poprzez przegląd wymagań. Prawdopodobnie poza
kontrolą
@ocodo: W ten sam sposób, w jaki oglądasz Obserwatorów. :)
Greg Burghardt

Odpowiedzi:

18

Testy są już przetestowane. Testy są z założenia chronione przed błędami, ponieważ testy wykrywają jedynie różnice między kodem a naszymi oczekiwaniami. W przypadku problemów mamy błąd. Błąd może znajdować się w kodzie lub z takim samym prawdopodobieństwem w testach.

  1. Istnieje kilka technik, które uniemożliwiają dodanie tego samego błędu zarówno w kodzie, jak i testach:

    1. Klient powinien być inną osobą niż realizator.
    2. Najpierw napisz testy, a następnie kod (jak w Test Driven Development).
  2. Nie musisz testować podstawowej platformy. Testy nie tylko wykonują kod napisany przez ciebie, ale również uruchamiają kod z platformy. Chociaż nie musisz łapać błędów na platformie testowej, bardzo trudno jest napisać kod i testy, które zawsze ukrywają błąd na platformie, innymi słowy bardzo trudno jest mieć systematyczny błąd zarówno w testach / kodzie, jak i na platformie, a prawdopodobieństwo zmniejsza się z każdym tworzonym testem. Nawet jeśli spróbujesz to zrobić, będziesz miał bardzo trudne zadanie.

  3. Możesz mieć błędy w testach, ale zwykle są one łatwo wychwytywane, ponieważ testy są testowane przez opracowany kod. Pomiędzy kodem a testami masz informacje zwrotne na temat samodzielnego egzekwowania. Oba przewidują, jak powinno się zachowywać określone wywołanie interfejsu. Jeśli odpowiedź jest inna, nie musisz mieć błędu w kodzie. Możesz również mieć błąd w teście.

raisercostin
źródło
Bardzo miła odpowiedź. Podoba mi się pomysł samowzmacniającej się pętli między testami a kodem oraz spostrzeżenie, że trudno byłoby pisać testy konsekwentnie ukrywające błędy na podstawowej platformie.
Ryszard Szopa
co nie zapobiega tworzeniu testów opartych na błędnych założeniach dotyczących tego, co powinien zrobić rzeczywisty kod. Co może prowadzić do bardzo nieprzyjemnych błędów, które pozostają niewykryte podczas testowania. Jedynym sposobem, aby temu zapobiec, jest napisanie testów przez osobę trzecią, bez żadnego związku z organizacją piszącą rzeczywisty kod, aby nie mogły „zanieczyszczać” nawzajem swoich myśli, jeśli chodzi o interpretację dokumentów wymagań.
jwenting
24

Staraj się, aby poszczególne testy były jak najmniejsze (krótkie).

Powinno to przede wszystkim zmniejszyć ryzyko wystąpienia błędu. Nawet jeśli uda Ci się go utworzyć, łatwiej go znaleźć. Testy jednostkowe powinny być małe i specyficzne, z niską tolerancją na awarie i odchylenia.

Ostatecznie jest to prawdopodobnie kwestia doświadczenia. Im więcej testów piszesz, tym lepiej się w tym stajesz, tym mniejsza jest szansa na zrobienie z nich kiepskich testów.

dr Hannibal Lecter
źródło
3
Co jeśli testy wymagają nieco skomplikowanej konfiguracji? Czasami tego rodzaju rzeczy nie są pod twoją kontrolą.
Ryszard Szopa
Domyślam się, że skomplikowana konfiguracja to „stan początkowy” testów. Jeśli to się nie powiedzie, wszystkie testy powinny zakończyć się niepowodzeniem. Właściwie pracuję teraz nad takim projektem, a ludzie, którzy nigdy nie korzystali z testów jednostkowych, ciągle pytali o to samo… dopóki nie wyjaśniliśmy, jakie są testy jednostkowe :) Potem zdali sobie sprawę, że można to zrobić, pomimo ogromnych złożoność projektu.
dr Hannibal Lecter
Jaki jest najlepszy sposób, aby sprawdzić, czy ten „warunek początkowy” jest spełniony, jest właśnie sednem mojego pytania. Czy piszesz na to osobny test? Lub po prostu załóż, że testy się zakończą, jeśli ten warunek nie jest spełniony? Co z sytuacją, gdy konfiguracja nie jest „katastrofalnie” zła, tylko nieznacznie wyłączona?
Ryszard Szopa
2
Twoje testy powinny zakończyć się niepowodzeniem, jeśli początkowe warunki nie są właściwe, o to właśnie chodzi. W stanie Aoczekujesz rezultatu B. Jeśli nie masz stanu A, test powinien zakończyć się niepowodzeniem. W tym momencie możesz sprawdzić, dlaczego się nie udało, złe warunki początkowe lub zły test, ale w obu przypadkach powinno się nie udać. Nawet jeśli tak jest, jak mówisz, „lekko off” (to znaczy "A" => "B", "a" => "b"ale nigdy "a" => "B"lub Twój test jest złe).
dr Hannibal Lecter
19

Jedną z taktyk jest napisanie testu przed testowanym kodem i upewnienie się, że test zakończy się niepowodzeniem z właściwego powodu. Jeśli używasz TDD , powinieneś uzyskać przynajmniej ten poziom testowania testów.

Bardziej wyczerpującym sposobem przetestowania jakości zestawu testów jest użycie testu mutacji .

Don Roby
źródło
2
I że test kończy się niepowodzeniem z właściwego powodu .
Frank Shearar,
@Frank - Tak. Dodam to do odpowiedzi.
Don Roby
I dodajesz nowy test do przetestowania nowego zachowania. Nie dodawaj do istniejących testów.
Huperniketes
@DonRoby, czy uważasz, że testy mutacji są przydatne w praktyce? Jakie braki znalazłeś w swoich przypadkach testowych?
dzieciou
4

Dla # 1 i # 3: Testy jednostkowe nie powinny zawierać żadnej logiki, jeśli to zrobisz, prawdopodobnie testujesz więcej niż jedną rzecz w teście jednostkowym. Jedną z najlepszych praktyk w zakresie testów jednostkowych jest posiadanie tylko jednego testu na test jednostkowy.

Obejrzyj wideo Roy Osherove, aby dowiedzieć się więcej o tym, jak dobrze pisać testy jednostkowe.

Piers Myers
źródło
ad # 3 - Zgadzam się, że testy powinny być tak proste, jak to możliwe i nie powinny zawierać żadnej logiki. Pomyśl jednak o fazie konfiguracji testu, gdy tworzysz obiekty, które będą potrzebne. Możesz tworzyć lekko niewłaściwe obiekty. O takich problemach myślę.
Ryszard Szopa
Kiedy mówisz „nieco niewłaściwe obiekty”, czy masz na myśli, że stan obiektu jest nieprawidłowy lub czy rzeczywisty projekt obiektu jest nieprawidłowy? Dla stanu obiektu można prawdopodobnie napisać testy, aby sprawdzić jego poprawność. Jeśli projekt jest nieprawidłowy, test powinien zakończyć się niepowodzeniem.
Piers Myers
3

Pod względem # 1 - myślę, że dobrym pomysłem jest sparowanie / sprawdzenie kodu dla tej strony. Łatwo jest założyć z góry założenia lub po prostu źle się pomylić, ale jeśli musisz wyjaśnić, co robi test, o co chodzi, bardziej prawdopodobne jest, że podejmiesz, jeśli celujesz w niewłaściwy cel.

Sam J
źródło
2

Musi istnieć moment, w którym należy przestać próbować przeprowadzać test jednostkowy. Powinien wiedzieć, kiedy narysować linię. Czy powinniśmy pisać przypadki testowe do testowania przypadków testowych? Co z nowymi przypadkami testowymi napisanymi do testowania przypadków testowych? Jak je przetestujemy?

if (0 > printf("Hello, world\n")) {
  printf("Printing \"Hello, world\" failed\n");
}

Edycja: zaktualizowano z objaśnieniami sugerowanymi przez komentarz.

aufather
źródło
-1 co? Wydaje się to nie mieć znaczenia.
alternatywnie
2
Musi istnieć moment, w którym należy przestać próbować przeprowadzać test jednostkowy. Powinien wiedzieć, kiedy narysować linię. Czy powinniśmy pisać przypadki testowe do testowania przypadków testowych? Co z nowymi przypadkami testowymi napisanymi do testowania przypadków testowych? Jak je przetestujemy?
sierpień
2
Proces Mózg podniósł EInfiniteRecursion podczas próby ekstrapolacji twojego oświadczenia ...
Mason Wheeler,
Zastąp odpowiedź swoim komentarzem, a otrzymasz +1
Uwaga do siebie - wymyśl nazwę
3
Szczerze mówiąc, twoim przykładem jest słomiany człowiek. Testujesz podsystem printf () w bibliotece C, a nie rzeczywisty program wywołujący printf (). Zgadzam się jednak, że w pewnym momencie należy przerwać rekurencyjne testowanie testów.
Tim Post
2

Hej.
Musisz do aplikacji:

  • Twój produkt
  • Twój test dla tego produktu.

Kiedy przeprowadzasz testy na swoim produkcie, tak naprawdę nie interesuje Cię sam test, ale interakcja między twoim produktem a twoimi testami. Jeśli test się nie powiedzie, nie oznacza to, że aplikacja ma błąd. Mówi, że interakcja między produktem a testem nie powiodła się . Teraz Twoim zadaniem jest ustalić, co poszło nie tak. Może to być:

  • aplikacja nie działa zgodnie z oczekiwaniami (oczekiwanie wyrażone w teście)
  • aplikacja działa poprawnie, po prostu nie udokumentowałeś tego zachowania poprawnie (w swoich testach)

Dla mnie testy zakończone niepowodzeniem nie są prostą informacją zwrotną, że to i to jest złe . To wskaźnik niespójności i muszę zbadać oba, aby sprawdzić, czy coś poszło nie tak. Ostatecznie jestem odpowiedzialny za sprawdzenie, czy aplikacja jest poprawna, testy są tylko narzędziem do podkreślenia obszarów, które warto sprawdzić.

Testy sprawdzają tylko niektóre części aplikacji. Testuję aplikację, testuję testy.

yoosiba
źródło
2

Testy nie powinny być wystarczająco „inteligentne”, aby wykryć błędy.

Kod, który piszesz, implementuje zestaw specyfikacji. (Jeśli X, to Y, chyba że Z, w którym to przypadku Q itp.). Jedynym testem, jaki powinien próbować wykonać, jest ustalenie, że X naprawdę jest Y, chyba że Z, w którym to przypadku Q. Oznacza to, że wszystko, co powinien zrobić test, to ustawienie X i weryfikacja Y.

Ale to nie obejmuje wszystkich przypadków, prawdopodobnie mówisz i miałbyś rację. Ale jeśli sprawisz, że test będzie „wystarczająco inteligentny”, aby wiedzieć, że X powinien być tylko Y, jeśli nie Z, to w zasadzie ponownie wdrażasz logikę biznesową w teście. Jest to problematyczne z powodów, dla których przejdziemy nieco głębiej poniżej. Nie powinieneś poprawiać zasięgu kodu, czyniąc swój pierwszy test „inteligentniejszym”, zamiast tego dodaj drugi głupi test, który ustawia X i Z i weryfikuje Q. W ten sposób będziesz mieć dwa testy, jeden obejmujący ogólny przypadek ( czasami znany również jako ścieżka szczęścia) i taki, który obejmuje obudowę krawędzi jako osobny test.

Istnieje wiele przyczyn tego, przede wszystkim, w jaki sposób można ustalić, czy nieudany test jest spowodowany błędem w logice biznesowej lub błędem w testach? Oczywiście odpowiedź jest taka, że ​​jeśli testy są tak proste, jak to możliwe, jest mało prawdopodobne, że zawierają błędy. Jeśli uważasz, że twoje testy wymagają testowania, oznacza to, że testujesz źle .

Inne powody obejmują to, że po prostu replikujesz wysiłek (jak już wspomniałem, napisanie testu wystarczająco inteligentnego, aby wykorzystać wszystkie możliwości w jednym teście, to w zasadzie replikacja logiki biznesowej, którą próbujesz przetestować w pierwszej kolejności), jeśli wymagania się zmienią następnie testy powinny być łatwe do zmiany, aby odzwierciedlić nowe wymagania, testy służą jako rodzaj dokumentacji (są formalnym sposobem określenia specyfikacji testowanego urządzenia) i tak dalej.

TL: DR: Jeśli twoje testy wymagają testowania, robisz to źle. Napisz głupie testy .

GordonM
źródło
0

Nie jest to odpowiedź (nie mam prawa komentować), ale zastanawiałem się, czy nie zapomniałeś o innych przyczynach opracowania przypadków testowych ...
Po wykryciu wszystkich błędów w testach możesz łatwo przetestować aplikację regresyjnie. Zautomatyzowane zestawy testowe pomogłyby znaleźć problemy wcześniej, przed integracją. Zmiany wymagań są stosunkowo łatwiejsze do przetestowania, ponieważ zmiany mogą stać się nowszymi, zmienionymi wersjami starszych przypadków testowych, które przechodzą, a starsze przypadki pozostają w celu wykrycia awarii.

CMR
źródło
0

Krótka odpowiedź: kod produkcyjny testuje testy .

Porównaj to z modelem kredytowym / debetowym stosowanym w ekonomii. Mechanika jest bardzo prosta - jeśli kredyt różni się od debetu, coś jest nie tak.

to samo dotyczy testów jednostkowych - jeśli test się nie powiedzie, oznacza to, że coś jest nie tak. Może to być kod produkcyjny, ale równie dobrze może to być kod testowy! Ta ostatnia część, jeśli ważna.

Zauważ, że błędów typu (1) nie można znaleźć w testach jednostkowych. Aby uniknąć tego rodzaju błędów, potrzebujesz innych narzędzi.

vidstige
źródło