Załóżmy, że istnieje klasa narzędziowa, która udostępnia niektóre typowe metody statyczne używane wszędzie w kodzie przez wiele innych klas.
Jak zaprojektowałbyś swoje testy jednostkowe dla konsumentów narzędzia, aby ich testy zakończyły się niepowodzeniem, jeśli którykolwiek z testów narzędzia nie przejdzie pomyślnie? Czy możesz to zrobić, czy musisz sam sprawdzić, czy testy klasy użyteczności są zielone?
Na przykład mam narzędzie do dzielenia wiadomości, które jest używane (a raczej jego dane wyjściowe) przez analizator komunikatów. Chciałbym mieć pewność, że rozdzielacz komunikatów działa poprawnie, zanim parser komunikatów zostanie przetestowany.
Napisałem testy dla obu z nich, ale czy istnieje sposób na ich połączenie i uzależnienie jednego testu od wyniku innego testu?
Nie mogłem znaleźć odpowiedniego tagu, ale używam silnika testowego jednostki Visual Studio.
źródło
Odpowiedzi:
Nie ma sensu upewniać się, że każda usterka w systemie wyzwala dokładnie jeden test.
Zestaw testowy ma jedno zadanie: sprawdzenie, czy nie ma znanych wad. Jeśli wystąpi wada, nie ma znaczenia, czy jeden test się nie powiedzie, czy 10. Jeśli przyzwyczaisz się do niepowodzenia zestawu testów, jeśli spróbujesz ocenić, jak „zły” jest twój program, licząc testy zakończone niepowodzeniem, nie jesteś przy użyciu właściwego testu regresji. Pakiet testowy powinien przejść wszystkie testy przed opublikowaniem kodu.
Jedynym uzasadnionym powodem pominięcia testów jest to, że testują one niekompletną funkcjonalność i zajmują nadmiernie dużo czasu, który można by lepiej wykorzystać podczas wdrażania rzeczy, którą mają przetestować. (Jest to problem tylko wtedy, gdy nie ćwiczysz ścisłego programowania opartego na testach, ale to przecież właściwy wybór).
W przeciwnym razie nie zawracaj sobie głowy próbą przekształcenia zestawu testów w wskaźnik informujący dokładnie, co jest nie tak. To nigdy nie będzie dokładne i tak nie powinno być. Ma uchronić cię przed dwukrotnym popełnieniem tego samego błędu, to wszystko.
źródło
To zależy od twojego oprzyrządowania, ale prawdopodobnie nie możesz (i nie powinieneś)
Niektóre frameworki testów jednostkowych ( na przykład PHPUnit ) pozwalają na „łączenie” testów, tak aby test zakończony niepowodzeniem na jednym poziomie nie wykonywał innych testów. Wątpię jednak, aby to rozwiązało problem w tej sytuacji.
Niedopuszczenie do wykonania gwarantowanej kolejności testów wymusza izolowanie testów od siebie i jest ogólnie uważane za dobrą rzecz. Wyobraź sobie, co by się stało, gdyby testy nie tylko same się uruchomiły, ale także dostarczyły dane do innych testów, aby ...
Możesz umieścić te metody narzędziowe w osobnym rozwiązaniu lub kategorii testowej. Upewnij się, że wizualnie „wyróżniają się” w teście prowadzącym testy, lub że ta kategoria jest uruchamiana jako pierwsza i nie uruchamia żadnych innych testów, jeśli testy w tej kategorii zakończą się niepowodzeniem *. Gdy jeden z tych testów zakończy się niepowodzeniem, błąd prawdopodobnie spadnie kaskadowo we wszystkich testach i powinieneś upewnić się, że ktokolwiek uruchamia testy, wie, aby zacząć od naprawienia tych testów. To samo dotyczy testów jednostkowych i testów integracyjnych. Jeśli Unittest zawiedzie, kaskadowo wywoła różnego rodzaju chaos w testach integracji. Wszyscy wiedzą, że kiedy testy Unit AND Integration zakończą się niepowodzeniem, zacznij od sprawdzenia Unittests ...
* Za pomocą zautomatyzowanego skryptu kompilacji lub testu możesz najpierw uruchomić tę kategorię, sprawdzić wynik i uruchomić inne testy tylko, jeśli pierwsza partia testów przejdzie pomyślnie.
źródło
Spróbuj utrzymać atomowy test jednostkowy. Pamiętaj, że kod do automatycznego testowania jest również częścią twojej bazy kodu, ale sam nie jest testowany, więc postaraj się, aby był tak prosty i oczywisty, jak to możliwe.
Aby odpowiedzieć bardziej szczegółowo na twoje pytanie, nie ma gwarancji kolejności wykonywania testów, więc nie ma też sposobu, aby zagwarantować, że test użyteczności zakończy się sukcesem przed uruchomieniem pozostałych testów. Dlatego nie ma gwarantowanego sposobu na osiągnięcie tego, co chcesz, przy jednoczesnym posiadaniu jednego zestawu testów dla wszystkich testów.
Możesz przenieść narzędzia do własnego rozwiązania i dodać odwołanie do wynikowej biblioteki DLL w bieżącym projekcie.
źródło
Podsumowując, nie chcesz używać narzędzi / technik do robienia rzeczy innych niż te, do których są przeznaczone.
To, co próbujesz zrobić, brzmi jak problem, który można łatwo rozwiązać za pomocą praktyki CI (ciągłej integracji).
W ten sposób możesz zachować swoje testy atomowe, jak już sugerowano, i pozwolić CI zająć się weryfikacją testów.
Jeśli którykolwiek test zakończy się niepowodzeniem, możesz ustawić go tak, aby nie pozwalał na opublikowanie kodu.
źródło
Mam zwyczaj zawsze próbować odróżnić kod poziomu aplikacji od kodu poziomu środowiska, więc napotkałem problem, który opisujesz dość często: zwykle chcesz, aby cały kod poziomu środowiska był testowany, zanim jakikolwiek kod poziomu aplikacji zacznie być testowany . Ponadto, nawet w ramach kodu na poziomie frameworka, istnieją pewne podstawowe moduły frameworka, które są używane przez wszystkie inne moduły frameworka, a jeśli coś zawiedzie w podstawach, naprawdę nie ma sensu testować niczego innego.
Niestety, dostawcy platform testowych zwykle mają dość sztywne poglądy na temat tego, w jaki sposób ich twórczość ma być wykorzystywana, i raczej chronią te pomysły, podczas gdy ludzie, którzy używają ich frameworków, akceptują zamierzone użycie bez pytania. Jest to problematyczne, ponieważ hamuje eksperymenty i innowacje. Nie wiem o wszystkich innych, ale wolałbym mieć swobodę, aby spróbować zrobić coś w dziwny sposób i przekonać się, czy wyniki są lepsze czy gorsze niż ustalony sposób, niż nie mieć wolności róbcie wszystko po swojemu.
Tak więc, moim zdaniem, zależności testowe byłyby niesamowitą rzeczą, a zamiast tego możliwość określenia kolejności wykonywania testów byłaby następną najlepszą rzeczą.
Jedynym sposobem, w jaki znalazłem rozwiązanie problemu zamawiania testów, jest staranne nazewnictwo, aby wykorzystać tendencję ram testowania do wykonywania testów w kolejności alfabetycznej.
Nie wiem, jak to działa w Visual Studio, ponieważ jeszcze nie zrobiłem nic, co wymagałoby obszernych testów w języku C #, ale po stronie Java działa to w następujący sposób: pod folderem źródłowym projektu zwykle mamy dwa podfoldery, jeden o nazwie „główny” zawierający kod produkcyjny, a drugi o nazwie „test” zawierający kod testowy. Pod „main” mamy hierarchię folderów, która dokładnie odpowiada hierarchii pakietów naszego kodu źródłowego. Pakiety Java w przybliżeniu odpowiadają przestrzeniom nazw C #. C # nie wymaga dopasowania hierarchii folderów do hierarchii przestrzeni nazw, ale zaleca się to zrobić.
Teraz ludzie zwykle robią w świecie Java, że w folderze „test” odzwierciedlają hierarchię folderów znajdującą się w folderze „głównym”, dzięki czemu każdy test znajduje się w dokładnie tym samym pakiecie co testowana klasa. Uzasadnieniem tego jest to, że dość często klasa testująca musi mieć dostęp do prywatnych członków testowanej klasy, więc klasa testowa musi znajdować się w tym samym pakiecie co klasa testowana. Po stronie C # na świecie nie ma czegoś takiego jak widoczność lokalna w przestrzeni nazw, więc nie ma powodu, aby odzwierciedlać hierarchie folderów, ale myślę, że programiści C # mniej więcej przestrzegają tej samej dyscypliny w tworzeniu folderów.
W każdym razie uważam, że cały pomysł umożliwienia klasom testującym dostępu do lokalnych członków pakietów testowanych klas jest błędny, ponieważ mam tendencję do testowania interfejsów, a nie implementacji. Hierarchia folderów moich testów nie musi więc odzwierciedlać hierarchii folderów mojego kodu produkcyjnego.
Tak więc nazywam foldery (czyli pakiety) moich testów w następujący sposób:
Gwarantuje to, że wszystkie testy dla „SomeSubsystem” zostaną wykonane przed wszystkimi testami dla „SomeOtherSubsystem”, które z kolei wszystkie zostaną wykonane przed wszystkimi testami dla „AndYetAnotherSubsystem” i tak dalej, i tak dalej.
W folderze poszczególne pliki testowe mają następujące nazwy:
Oczywiście bardzo pomaga to, że współczesne IDE mają potężne możliwości refaktoryzacji, które pozwalają zmieniać nazwy całych pakietów (i wszystkich podpakietów oraz całego kodu, który się do nich odwołuje) za pomocą kilku kliknięć i naciśnięć klawiszy.
źródło
I don't know about everyone else, but I would prefer to have the freedom to try to do something in an odd way, and see for myself whether the results are better or worse
++ kolega. Nie wiem, czy podoba mi się to rozwiązanie, ale podoba mi się twoje nastawienie.