Badając najlepsze praktyki testowania jednostek, aby pomóc w opracowaniu wytycznych dla mojej organizacji, natknąłem się na pytanie, czy lepiej lub przydatniej jest oddzielić urządzenia testowe (klasy testowe) czy zachować wszystkie testy dla jednej klasy w jednym pliku.
Fwiw, mam na myśli „testy jednostkowe” w czystym sensie, że są to testy białych skrzynek ukierunkowane na jedną klasę, jedno stwierdzenie na test, wyśmiewane wszystkie zależności itp.
Przykładowym scenariuszem jest klasa (nazwij to Dokument), która ma dwie metody: CheckIn i CheckOut. Każda metoda implementuje różne reguły itp., Które kontrolują ich zachowanie. Zgodnie z regułą jednego potwierdzenia na test, będę miał wiele testów dla każdej metody. Mogę umieścić wszystkie testy w jednej DocumentTests
klasie o nazwach takich jak CheckInShouldThrowExceptionWhenUserIsUnauthorized
i CheckOutShouldThrowExceptionWhenUserIsUnauthorized
.
Mogę też mieć dwie osobne klasy testowe: CheckInShould
i CheckOutShould
. W takim przypadku moje nazwy testów zostałyby skrócone, ale byłyby zorganizowane, aby wszystkie testy dla określonego zachowania (metody) były razem.
Jestem pewien, że są plusy i minusy, aby podejść i zastanawiam się, czy ktoś poszedł tą drogą z wieloma plikami, a jeśli tak, to dlaczego? Lub, jeśli wybrałeś podejście z jednym plikiem, dlaczego uważasz, że jest to lepsze?
źródło
testResponseContainsSuccessTrue()
,testResponseContainsMyData()
atestResponseStatusCodeIsOk()
. Można by mieć je w jednymtestResponse()
, który trzy dochodzi:assertEquals(200, response.status)
,assertEquals({"data": "mydata"}, response.data)
iassertEquals(true, response.success)
Odpowiedzi:
Jest to rzadkie, ale czasem sensowne jest posiadanie wielu klas testowych dla danej klasy testowanej. Zazwyczaj robiłbym to, gdy wymagane są różne konfiguracje i dzielone w ramach podzbioru testów.
źródło
Naprawdę nie widzę żadnego istotnego powodu, dla którego miałbyś podzielić test dla jednej klasy na wiele klas testowych. Ponieważ głównym celem powinno być utrzymanie spójności na poziomie klasy, powinieneś dążyć do tego również na poziomie testowym. Kilka przypadkowych powodów:
źródło
Jeśli jesteś zmuszony podzielić testy jednostkowe dla klasy na wiele plików, może to wskazywać, że sama klasa jest źle zaprojektowana. Nie mogę wymyślić żadnego scenariusza, w którym bardziej korzystne byłoby podzielenie testów jednostkowych dla klasy, która w rozsądny sposób przestrzega zasady pojedynczej odpowiedzialności i innych dobrych praktyk programistycznych.
Co więcej, dłuższe nazwy metod w testach jednostkowych są dopuszczalne, ale jeśli ci to przeszkadza, zawsze możesz przemyśleć konwencję nazewnictwa testów jednostkowych, aby skrócić nazwy.
źródło
Jednym z moich argumentów przeciwko podzieleniu testów na wiele klas jest to, że trudniej jest innym programistom w zespole (szczególnie tym, którzy nie są tak doświadczeni w testowaniu) zlokalizowanie istniejących testów ( Gee, zastanawiam się, czy jest już test na to metoda? Zastanawiam się, gdzie by to było? ), a także gdzie umieścić nowe testy ( zamierzam napisać test dla tej metody w tej klasie, ale nie jestem pewien, czy powinienem umieścić je w nowym pliku, czy w istniejącym jeden? )
W przypadku, gdy różne testy wymagają drastycznie różnych ustawień, widziałem, jak niektórzy praktykujący TDD umieszczają „urządzenie” lub „konfigurację” w różnych klasach / plikach, ale nie same testy.
źródło
Chciałbym móc zapamiętać / znaleźć link, w którym technika, którą wybrałem, została po raz pierwszy zademonstrowana. Zasadniczo tworzę jedną, abstrakcyjną klasę dla każdej testowanej klasy, która zawiera zagnieżdżone urządzenia testowe (klasy) dla każdego testowanego elementu. Zapewnia to pierwotnie pożądaną separację, ale zachowuje wszystkie testy w tym samym pliku dla każdej lokalizacji. Ponadto generuje to nazwę klasy, która umożliwia łatwe grupowanie i sortowanie w module testowym.
Oto przykład zastosowania tego podejścia do mojego oryginalnego scenariusza:
Powoduje to pojawienie się następujących testów na liście testów:
W miarę dodawania kolejnych testów można je łatwo grupować i sortować według nazw klas, co powoduje, że wszystkie testy dla badanej klasy są wymienione razem.
Kolejną zaletą tego podejścia, które nauczyłem się wykorzystywać, jest zorientowany obiektowo charakter tej struktury, co oznacza, że mogę zdefiniować kod w metodach uruchamiania i czyszczenia klasy bazowej DocumentTests, które będą współużytkowane przez wszystkie klasy zagnieżdżone, a także wewnątrz każdej zagnieżdżona klasa dla zawartych w niej testów.
źródło
Spróbuj pomyśleć przez odwrót.
Dlaczego miałbyś mieć tylko jedną klasę testową na klasę? Czy przeprowadzasz test klasowy czy test jednostkowy? Czy w ogóle zależysz na zajęciach ?
Test jednostkowy powinien testować określone zachowanie w określonym kontekście. Fakt, że twoja klasa już ma
CheckIn
środki, powinien zapewnić zachowanie, które tego potrzebuje.Jak byś pomyślał o tym pseudokodzie:
Teraz nie testujesz bezpośrednio tej
checkIn
metody. Zamiast tego testujesz zachowanie (które jest na szczęście do sprawdzenia;)), a jeśli potrzebujesz przefakturowaćDocument
i podzielić je na różne klasy lub scalić inną klasę, pliki testowe są nadal spójne, nadal mają sens, ponieważ nigdy nie zmieniasz logiki podczas refaktoryzacji, tylko struktura.Jeden plik testowy dla jednej klasy po prostu utrudnia refaktoryzację, gdy jest to potrzebne, a testy mają również mniej sensu pod względem domeny / logiki samego kodu.
źródło
Zasadniczo zalecałbym myślenie o testach jako o testowaniu zachowania klasy, a nie o metodzie. Tzn. Niektóre z twoich testów mogą wymagać wywołania obu metod w klasie w celu przetestowania niektórych oczekiwanych zachowań.
Zwykle zaczynam od jednej klasy testów jednostkowych na klasę produkcyjną, ale ostatecznie mogę podzielić tę klasę testów jednostkowych na kilka klas testowych w oparciu o testowane zachowanie. Innymi słowy, odradzałbym dzielenie klasy testowej na CheckInShould i CheckOutShould, a raczej dzielenie według zachowania testowanej jednostki.
źródło
1. Zastanów się, co może pójść nie tak
Podczas początkowego rozwoju dość dobrze wiesz, co robisz, i oba rozwiązania prawdopodobnie będą w porządku.
Staje się bardziej interesujący, gdy test kończy się niepowodzeniem po zmianie znacznie później. Istnieją dwie możliwości:
CheckIn
(lubCheckOut
). Ponownie, zarówno rozwiązanie dla jednego pliku, jak i dla dwóch plików jest w tym przypadku OK.CheckIn
iCheckOut
(i być może ich testy) w sposób, który ma sens dla każdego z nich, ale nie dla obu razem. Złamałeś spójność pary. W takim przypadku podzielenie testów na dwa pliki utrudni zrozumienie problemu.2. Zastanów się, do jakich testów są używane
Testy służą dwóm głównym celom:
Więc?
Obie te perspektywy sugerują, że wspólne testowanie może pomóc, ale nie zaszkodzi.
źródło