2009-07-03 10 views
8

Jako kontynuację dyskusji w komentarzach this answer, czy test TDD zawsze musi być zakończony niepowodzeniem?Czy test TDD zawsze powinien zakończyć się niepowodzeniem?

Rozważmy następujący przykład. Jeśli piszę implementację LinkedHashSet i jeden test testowy, który po wstawieniu duplikatu, oryginał jest w tej samej kolejności iteracji co przed wstawieniem, może chciałbym dodać osobny test, że duplikat w ogóle nie jest w zestawie.

Pierwszy test zostanie zauważony jako pierwszy, a następnie zaimplementowany.

Problem polega na tym, że implementacja pierwszego przejścia testowego wykorzystała inną implementację zestawu do przechowywania danych, więc jako efekt uboczny przechodzi już drugi test.

Myślę, że głównym celem testu nie jest zapewnienie, że test jest dobrym testem (wielokrotnie napisałem test, który według mnie może się nie powieść, ale nie, ponieważ test został napisany nieprawidłowo) . Ale jeśli masz pewność, że test, który piszesz, rzeczywiście coś testuje, czy nie jest to cenne, aby upewnić się, że nie złamiesz tego zachowania później?

+0

Jestem co najwyżej dynamicznym żółtodziobem (stąd komentarz zamiast odpowiedzi), ale moje odczucie jest - tak dla dynamicznych języków i zależy od języków statycznych. Kod, który nie powiedzie się kompilacji w języku statycznym, będzie działał w dynamicznym języku, ale spowoduje niepowodzenie testu. Aby uruchomić język statyczny, musisz dodać pewien rodzaj zachowania bazowego do testowanego kodu (nawet jeśli są to tylko metody puste), które MOGĄ spowodować, że poprawnie napisany test przejdzie jako pierwszy. –

Odpowiedz

9

Oczywiście, że jest cenny, ponieważ wtedy jest przydatny regression test. Moim zdaniem testy regresji są ważniejsze niż testowanie nowo opracowanego kodu.

Powiedzieć, że zawsze muszą zawodzić, to przekraczać praktyczność.

4

TDD jest dla mnie raczej narzędziem do projektowania, a nie po namyśle. Więc nie ma innej drogi, test zakończy się niepowodzeniem, ponieważ nie ma kodu, który jeszcze umożliwiałby przejście, dopiero po utworzeniu go, że test może kiedykolwiek przejść.

6

Tak, testy TDD muszą zakończyć się niepowodzeniem, zanim staną się zielone (praca). W przeciwnym razie nie wiesz, czy masz ważny test.

+0

Nie zgadzam się - weź statyczny język, w którym masz test typu some_value_should_always_be_false(). Napisanie wystarczającej ilości kodu, aby kompilacja testu prawdopodobnie również sprawi, że test przejdzie, chyba że celowo sabotujesz test i ustawisz wartość testowaną na true. –

+2

Jak więc adresować scenariusze takie jak przedstawione w PO? – Yishai

+1

@Jeremy Frey - Nie możesz sabotować testów, aby niepowodzenie pierwszego testu. Celem nie jest sam język, ale przetestowanie logiki. W podanym przykładzie test wydaje się zbyt trywialny, aby dodać wartość, jeśli można założyć, że wartość zawsze będzie fałszywa. Mam nadzieję, że to pomoże. –

4

Myślę, że celem "niepowodzenia na początku" jest uniknięcie żartowania, że ​​test zadziałał. Jeśli masz zestaw testów sprawdzających tę samą metodę z różnymi parametrami, jeden (lub więcej) z nich prawdopodobnie przejdzie od samego początku. Rozważmy następujący przykład:

public String doFoo(int param) { 
    //TODO implement me 
    return null; 
} 

Testy byłoby coś jak:

public void testDoFoo_matches() { 
    assertEquals("Geoff Hurst", createBar().doFoo(1966)); 
} 

public void testDoFoo_validNoMatch() { 
    assertEquals("no match", createBar().doFoo(1)); 
} 

public void testDoFoo_outOfRange() { 
    assertEquals(null, createBar().doFoo(-1)); 
} 
public void testDoFoo_tryAgain() { 
    assertEquals("try again", createBar().doFoo(0)); 
} 

Jeden z tych testów minie, ale wyraźnie inni nie, więc trzeba zaimplementować kod odpowiednio dla zestaw testów do zaliczenia. Myślę, że to jest prawdziwy wymóg. Duch reguły polega na upewnieniu się, że myślisz o oczekiwanym wyniku, zanim zaczniesz hackować.

+0

@John jakie zmiany wprowadziłeś? przed i po wyglądają tak samo dla mnie –

+0

@Rich: dodał kilka nawiasów. Możesz kliknąć link obok "edytowane", pokazując, jak dawno temu był edytowany (tuż nad jego nazwą), a zobaczysz wszystkie różnice i notatkę edycji. –

+0

@Ahmad, to właśnie zrobiłem, o ile potrafię powiedzieć tekst z przekreśleniem, a nowy tekst jest taki sam (skopiowano i wkleiłem pierwszą zmianę poniżej bez formatowania) createBar(). DoFoo (1966) createBar(). doFoo (1966). Co przeoczyłem –

0

IMHO, najważniejszą przyczyną niepowodzenia jest upewnienie się, że stworzony test nie ma wad. Możesz na przykład zapomnieć o Asercie w teście i być może nigdy nie dowiesz się o tym.

Podobny przypadek występuje, gdy przeprowadzasz testy graniczne, masz już wbudowany kod, który go obejmuje, ale zaleca się przetestowanie tego.

Myślę, że to nie jest duży problem, aby twój test się nie powiódł, ale musisz upewnić się, że rzeczywiście testuje to, co powinien (może debugowanie).

1

To, o co właściwie pytasz, to jak przetestować test, aby sprawdzić, czy jest on ważny i sprawdza, co zamierzasz.

Włączenie tego błędu jest możliwe, ale pamiętaj, że nawet jeśli nie powiedzie się, gdy planujesz, że zawiedzie i powiedzie się po przeliczeniu kodu, aby odnieść sukces, to nadal nie oznacza, że ​​twój test faktycznie testowałem to, co chciałeś ... Oczywiście możesz napisać kilka innych klas, które zachowują się inaczej, aby przetestować twój test ... Ale to jest faktycznie test, który testuje twój oryginalny test - Skąd wiesz, że test nowy jest ważny? :-)

Wykonywanie pierwszego testu nie jest dobrym pomysłem, ale nadal nie jest niezawodne.

Powiązane problemy