Czy pojedyncze testy jednostkowe nie łamią zasady DRY?

12

Ilekroć piszę testy jednostkowe, zawsze próbowałem mieć jeden assert na test, aby ułatwić debugowanie w przypadku niepowodzenia testów. Jednak postępując zgodnie z tą zasadą, mam wrażenie, że ciągle kopiuję ten sam kod w każdym teście i mając więcej testów, trudniej jest wrócić do czytania i utrzymania.

Czy testowanie pojedynczych stwierdzeń narusza DRY?

I czy jest jakaś dobra zasada, aby znaleźć właściwą równowagę, na przykład mając tylko jeden test na metodę ? *

* Zdaję sobie sprawę, że prawdopodobnie nie ma jednego uniwersalnego rozwiązania tego problemu, ale czy istnieje zalecany sposób rozwiązania tego problemu?

Korey Hinton
źródło
5
Możesz wyodrębnić skopiowany kod do metod
Ismail Badawi
@IsmailBadawi to brzmi jak dobry pomysł. Zakładam, że te metody powinny zwrócić instancję obiektu klasy, który
testuję
1
Tworzysz coś w danym stanie do przetestowania? To brzmi jak urządzenie.
Dave Hillier
@DaveHillier tak, nauczyłem się dzisiaj nowego słowa. Dzięki :)
Korey Hinton
zależy od tego, jak interpretujesz 1 aser na test, jeśli masz na myśli jedno wywołanie Assert *, to tak, jeśli chcesz również upewnić się, że niezmienniki nadal zachowują (następnie ponownie wyodrębnij to do metody), lub jeśli istnieje wiele efektów, które możesz po prostu „ t przetestować w jednym Assert (a jeśli tak, to nie byłoby jasne, dlaczego się nie udało)
maniak ratchet

Odpowiedzi:

14

Właściwe testy jednostkowe mają konwencję nazewnictwa, która pomaga natychmiast zidentyfikować, co się nie udało:

public void AddNewCustomer_CustomerExists_ThrowsException()

Dlatego masz jedno stwierdzenie na test, aby każda metoda (i jej nazwa) odpowiadała warunkowi, który twierdzisz.

Jak słusznie zauważyłeś, każdy nowy test będzie miał podobny kod instalacyjny. Podobnie jak w przypadku każdego kodu, możesz przefakturować wspólny kod na własną metodę, aby zmniejszyć lub wyeliminować duplikację i uczynić kod bardziej SUCHYM. Niektóre ramy testowe są specjalnie zaprojektowane, aby umożliwić umieszczenie tego kodu instalacyjnego w jednym miejscu .

W TDD żaden test nie jest YAGNI, ponieważ piszesz testy oparte tylko na tym, czego wymaga Twój kod. Jeśli go nie potrzebujesz, nie napiszesz testu.

Robert Harvey
źródło
Refaktoryzacja do jednej metody brzmi dobrze. Gdybym potrzebował instancji klasy w określonym stanie, mógłbym utworzyć i zwrócić nową instancję tego obiektu w refaktoryzowanej metodzie lub, jak sugerujesz, użyć metod dostarczonych przez środowisko testowe do wstępnej konfiguracji testu.
Korey Hinton
w twoim ostatnim punkcie jestem pewien, że mógłbym napisać testy funkcjonalności, które chciałbym mieć w kodzie, a nie funkcjonalności, której potrzebował
joelb
5

Czy testowanie pojedynczych stwierdzeń narusza DRY?

Nie, ale promuje naruszenie.

To powiedziawszy, dobry obiektowy projekt zwykle wychodzi poza okno do testów jednostkowych - głównie z ważnego powodu. Ważniejsze jest, aby testy jednostkowe były od siebie izolowane, aby można je było przesłuchiwać w izolacji i, w razie potrzeby, naprawić, mając pewność, że nie przełamiesz innych testów. Zasadniczo poprawność i czytelność testu jest ważniejsza niż jego rozmiar lub łatwość konserwacji.

Szczerze mówiąc, nigdy nie byłem fanem jednego twierdzenia na regułę testową z powodów, które opisujesz: prowadzi to do dużej ilości kodu płyty kotłowej, która jest trudna do odczytania, łatwa do złego gotowania i trudna do poprawienia, jeśli refaktoryzujesz (co zmusza Cię do mniejszego refaktoryzacji).

Jeśli funkcja ma zwrócić listę „foo” i „bar” dla danych wejściowych, ale w dowolnej kolejności doskonale jest użyć dwóch twierdzeń, aby sprawdzić, czy oba są w zestawie wyników. Problemem jest sytuacja, gdy pojedynczy test sprawdza dwa sygnały wejściowe lub dwa skutki uboczne i nie wiesz, który z nich spowodował błąd.

Uważam to za wariację zasady pojedynczej odpowiedzialności: powinna istnieć tylko jedna rzecz, która może spowodować niepowodzenie testu, aw idealnym świecie zmiana ta powinna przerwać tylko jeden test.

Ale ostatecznie jest to kompromis. Czy bardziej prawdopodobne jest, że poświęcisz więcej czasu na przechowywanie całego kodu pastey, czy też poświęcisz więcej czasu na poszukiwanie przyczyn źródłowych, gdy testy mogą zostać zerwane przez wiele źródeł. Tak długo, jak piszesz niektóre testy, prawdopodobnie nie ma to większego znaczenia. Pomimo mojej pogardy dla testów z jednym twierdzeniem, mam tendencję do popełniania błędów po stronie większej liczby testów. Twój przebieg może się różnić.

Telastyn
źródło
1
W przypadku testów ważniejsze jest, aby być DAMP niż DRY (opisowe i znaczące zwroty).
Jörg W Mittag
2

Nie. Wydaje się, że tak właśnie robisz. Chyba że znalazłeś godne uwagi odniesienie, w którym twierdzą, że jest to dobra praktyka.

Użyj urządzenia testowego (chociaż w terminologii XUnit zestaw testów, konfiguracja i rozrywanie to urządzenie), to znaczy niektóre ustawienia lub przykłady, które dotyczą wszystkich twoich testów.

Użyj metod takich jak zwykle, aby ustrukturyzować swój kod. Podczas testów refaktoryzacji nie stosuje się zwykłego refaktora TDD czerwono-zielonego , zamiast tego stosuje się „Refaktoryzacja na czerwono”. To jest,

  1. celowo przerwać test,
  2. dokonaj refaktoryzacji
  3. napraw swój test

W ten sposób wiesz, że testy nadal dają pozytywne i negatywne wyniki.

Istnieje kilka standardowych formatów testów. Na przykład Arrange, Act, Assert lub Given When, Then (BDD) . Rozważ zastosowanie oddzielnej funkcji dla każdego kroku. Powinieneś być w stanie wywołać funkcję zmniejszania płyty kotła.

Dave Hillier
źródło