Wywołany tym wątkiem (ponownie) myślę o tym, by w końcu zastosować testy jednostkowe w moich projektach. Kilka plakatów mówi coś w stylu „Testy są fajne, jeśli są dobre testy”. Moje pytanie teraz: co to są „dobre” testy?
W moich aplikacjach główną częścią często jest pewnego rodzaju analiza numeryczna, w zależności od dużych ilości zaobserwowanych danych, i skutkująca funkcją dopasowania, której można użyć do modelowania tych danych. Szczególnie trudno mi było zbudować testy dla tych metod, ponieważ liczba możliwych danych wejściowych i wyników jest zbyt duża, aby przetestować każdy przypadek, a same metody są często dość długie i nie można ich łatwo zrefaktoryzować bez poświęcania wydajności. Szczególnie interesują mnie „dobre” testy dla tego rodzaju metody.
źródło
Odpowiedzi:
Sztuka testów jednostkowych ma następujące zdanie na temat testów jednostkowych:
a następnie dodaje, że powinien być w pełni zautomatyzowany, godny zaufania, czytelny i łatwy w utrzymaniu.
Zdecydowanie polecam przeczytanie tej książki, jeśli jeszcze tego nie zrobiłeś.
Moim zdaniem wszystkie te są bardzo ważne, ale trzy ostatnie (godne zaufania, czytelne i możliwe do utrzymania), zwłaszcza, że jeśli twoje testy mają te trzy właściwości, to twój kod zwykle je również ma.
źródło
It should run at the push of a button
, czy to oznacza, że test jednostkowy nie powinien wymagać działania kontenerów (serwera aplikacji) (dla testowanej jednostki) lub połączenia zasobów (takich jak DB, zewnętrzne usługi sieciowe itp.)? Jestem tylko zdezorientowany, które części aplikacji powinny być testowane jednostkowo, a które nie. Powiedziano mi, że testy jednostkowe nie powinny zależeć od połączenia DB i działających kontenerów, a może zamiast tego mogą być używane makiety.Dobry test jednostkowy nie odzwierciedla funkcji, którą testuje.
Jako bardzo uproszczony przykład, rozważ, że masz funkcję, która zwraca średnią z dwóch liczb całkowitych. Najbardziej wszechstronny test wywołałby funkcję i sprawdziłby, czy wynik jest w rzeczywistości średnią. To nie ma żadnego sensu: dublujesz (replikujesz) testowaną funkcjonalność. Jeśli popełniłeś błąd w funkcji głównej, popełnisz ten sam błąd w teście.
Innymi słowy, jeśli replikujesz główną funkcjonalność w teście jednostkowym, jest to prawdopodobnie znak, że marnujesz swój czas.
źródło
Dobre testy jednostkowe to w zasadzie specyfikacja w postaci możliwej do uruchomienia:
Przekonałem się, że Test-Driven-Development jest bardzo dobrze dostosowany do procedur bibliotecznych, ponieważ zasadniczo piszesz najpierw interfejs API, a następnie rzeczywistą implementację.
źródło
w przypadku TDD „dobre” funkcje testowe , których chce klient ; funkcje niekoniecznie odpowiadają funkcjom, a programista nie powinien tworzyć scenariuszy testowych w próżni
w twoim przypadku - zgaduję - „funkcją” jest to, że funkcja dopasowania modeluje dane wejściowe z pewną tolerancją błędu. Ponieważ nie mam pojęcia, co naprawdę robisz, coś wymyślam; miejmy nadzieję, że jest to przeciwwskazane.
Przykładowa historia:
Idź więc porozmawiać z pilotami (i z komputerem docelowym, jeśli czujesz). Najpierw mówisz o tym, co „normalne”, a potem o tym, co nienormalne. Dowiesz się, co naprawdę ma znaczenie w tym scenariuszu, co jest wspólne, co jest mało prawdopodobne i co jest po prostu możliwe.
Powiedzmy, że normalnie będziesz miał półsekundowe okno na siedem kanałów danych telemetrycznych: prędkość, skok, przechylenie, odchylenie, wektor docelowy, rozmiar celu i prędkość celu, i że te wartości będą stałe lub zmieniają się liniowo. Nienormalnie możesz mieć mniej kanałów i / lub wartości mogą się szybko zmieniać. Więc razem wymyślić niektórych badań, takich jak:
Być może zauważyłeś, że nie ma scenariusza dla konkretnej sytuacji opisanej w historii. Okazuje się, po rozmowie z klientem i innymi interesariuszami, że cel w oryginalnej historii był tylko hipotetycznym przykładem. Prawdziwe testy wyszły z późniejszej dyskusji. To może się zdarzyć. Historia powinna zostać napisana od nowa, ale nie musi tak być [ponieważ jest ona jedynie symbolem zastępczym do rozmowy z klientem].
źródło
Utwórz testy dla przypadków narożnych, takich jak zestaw testowy zawierający tylko minimalną liczbę danych wejściowych (możliwe 1 lub 0) i kilka standardowych przypadków. Te testy jednostkowe nie zastępują dokładnych testów akceptacyjnych, ani nie powinny.
źródło
Widziałem wiele przypadków, w których ludzie poświęcają wiele wysiłku na pisanie testów rzadko wprowadzanego kodu, a nie na pisanie testów często wprowadzanego kodu.
Zanim usiądziesz, aby napisać jakieś testy, powinieneś spojrzeć na jakiś wykres połączeń, aby upewnić się, że planujesz odpowiedni zasięg.
Ponadto nie wierzę w pisanie testów tylko po to, aby powiedzieć „Tak, testujemy to”. Jeśli korzystam z biblioteki, która została upuszczona i pozostanie niezmienna, nie będę marnować dnia na pisanie testów, aby upewnić się, że wewnętrzne funkcje interfejsu API, które nigdy się nie zmienią, działają zgodnie z oczekiwaniami, nawet jeśli niektóre części wysoko na wykresie połączeń. Testy, które spożywają wspomnianej biblioteki (mój własny kod) wskazują na to.
źródło
Nie do końca TDD, ale po przejściu do kontroli jakości możesz poprawić swoje testy, konfigurując przypadki testowe w celu odtworzenia błędów, które pojawią się podczas procesu kontroli jakości. Może to być szczególnie cenne, gdy korzystasz z długoterminowego wsparcia i zaczynasz docierać do miejsca, w którym ryzykujesz, że ludzie przypadkowo przywrócą stare błędy. Przeprowadzenie testu uchwycenia jest szczególnie cenny.
źródło
Staram się, aby każdy test testował tylko jedną rzecz. Staram się nadawać każdemu testowi nazwę jak shouldDoSomething (). Próbuję przetestować zachowanie, a nie implementację. Testuję tylko metody publiczne.
Zwykle mam jeden lub kilka testów na sukces, a potem może garść testów na porażkę, według metody publicznej.
Często używam makiet. Dobra mock-framework prawdopodobnie byłaby bardzo pomocna, na przykład PowerMock. Chociaż jeszcze nie używam.
Jeśli klasa A używa innej klasy B, dodałbym interfejs X, aby A nie używał B bezpośrednio. Następnie stworzyłbym makietę XMockup i użyłem jej zamiast B w moich testach. Naprawdę pomaga przyspieszyć wykonywanie testów, zmniejsza złożoność testów, a także zmniejsza liczbę testów, które piszę dla A, ponieważ nie muszę radzić sobie ze specyfiką B. Mogę na przykład przetestować, że A wywołuje X.someMethod () zamiast efektu ubocznego wywołania B.someMethod ().
Utrzymuj również kod testowy w czystości.
Podczas korzystania z interfejsu API, takiego jak warstwa bazy danych, wyśmiewałbym go i umożliwiałam makietowi rzucanie wyjątku przy każdej możliwej okazji na polecenie. Następnie uruchamiam jeden test bez rzucania, a następnie w pętli, za każdym razem rzucając wyjątek przy następnej okazji, aż test ponownie się powiedzie. Trochę jak testy pamięci dostępne dla Symbiana.
źródło
Widzę, że Andry Lowry opublikował już wyniki testów jednostkowych Roya Osherove'a; ale wygląda na to, że nikt nie przedstawił (komplementarnego) zestawu, który wujek Bob podaje w Clean Code (132-133). Używa akronimu FIRST (tutaj z moimi streszczeniami):
źródło