jakie funkcje i / lub klasy są niemożliwe do przetestowania jednostkowego i dlaczego

21

Główną wymówką dewelopera za brak dobrych testów jednostkowych jest „Kod nie został zaprojektowany w sposób testowany przez jednostkę”. Próbuję zrozumieć, jakiego typu projekt i kod nie mogą być testowane jednostkowo.

manizzzz
źródło
2
Twoja wymówka? Współpracownicy? Menedżerowie? W jakim języku / frameworku pracujesz?
1
Dużo starszego kodu w aplikacji i brak czasu na przeprojektowanie.
knut
4
@gnat: Nie zgadzam się. Przytoczone przez ciebie pytanie dotyczy sytuacji, w których testy jednostkowe nie są przydatne. Obecne pytanie dotyczy sytuacji, które utrudniają testy jednostkowe.
Arseni Mourzenko,
@MainMa podobno czytamy różne pytania. „Próbuję zrozumieć, jakiego typu projekt i kod nie mogą być testowane jednostkowo”. => „Kiedy nie należy testować jednostkowo?”
komar
1
@manizzzz: możesz to zmienić w pytaniu.
jmoreno

Odpowiedzi:

27

Kilka czynników może utrudniać testowanie kodu. W takim przypadku refaktoryzacja pomaga ulepszyć kod, aby był testowalny.

Kilka przykładów kodu, który prawdopodobnie byłby trudny do przetestowania:

  • Funkcja 1000-LOC,
  • Kod, który w dużej mierze opiera się na stanie globalnym,
  • Kod, który wymaga konkretnego, skomplikowanego do budowy obiektów, takich jak kontekst bazy danych, zamiast polegać na interfejsach i wstrzykiwaniu zależności,
  • Kod, który działa wolno ,
  • Kod spaghetti,
  • Stary kod, który był modyfikowany przez lata bez dbałości o czytelność i łatwość konserwacji,
  • Trudno zrozumieć kod, który nie ma komentarzy ani wskazówek na temat pierwotnej intencji autora (na przykład kod, który używa nazw zmiennych, takich jak function pGetDp_U(int i, int i2, string sText).

Zauważ, że brak przejrzystej architektury nie sprawia, że ​​kod jest trudny do testowania jednostkowego, ponieważ testy jednostkowe dotyczą małych części kodu. Niejasna architektura nadal miałaby negatywny wpływ na integrację i testowanie systemu.

Arseni Mourzenko
źródło
8
Trudno też przetestować kod, który nie wstrzykuje zależności od nieoczyszczonych funkcji, takich jak liczby losowe, bieżący czas, wbudowane we / wy itp.
9000
trywialne jest testowanie takiego kodu - potrzebujesz tylko odpowiedniego narzędzia testowego, a nie zmieniania kodu, aby go dopasować. Wypróbuj Microsoft Fakes na przykład.
gbjbaanb
@MainMa, podoba mi się ta odpowiedź. Czy zechciałbyś również skomentować nieco, jakie czynniki popychają różne testy do integracji i testowania systemu? Wiem, że powodem, dla którego zadawałem podobne pytania do tego tutaj w przeszłości, jest to, że nie miałem mapy drogowej wyjaśniającej, jakie rodzaje testów najlepiej umieścić gdzie (a może najbardziej opłacalnie umieścić gdzie) - pomyślałem testy jednostkowe były jedyne w swoim rodzaju.
J Trana
14

Istnieje wiele rzeczy, które utrudniają testowanie kodu. Przypadkowo wiele z nich utrudnia także utrzymanie kodu:

  • Naruszenia prawa Demeter .
  • Tworzenie obiektów w metodzie zamiast wstrzykiwania zależności .
  • Szczelne połączenie.
  • Słaba spójność.
  • Polega w dużej mierze na skutkach ubocznych.
  • Polega głównie na globals lub singletonach.
  • Nie ujawnia wielu pośrednich wyników. (Kiedyś musiałem przetestować jednostronnie dziesięciostronicową funkcję matematyczną z pojedynczym wyjściem i bez dostępnych wyników pośrednich. Moi poprzednicy w zasadzie zakodowali niezależnie od odpowiedzi, jaką podał kod).
  • Zależy w dużej mierze bezpośrednio od usług, które trudno wyśmiewać, takich jak bazy danych.
  • Środowisko wykonawcze różni się znacznie od środowiska programistycznego, takie jak osadzony cel.
  • Jednostki dostępne tylko w skompilowanej formie (np. DLL innej firmy).
Karl Bielefeldt
źródło
Myślę, że to doskonała odpowiedź. Dotykasz wielu problemów na poziomie kodu i problemów związanych ze stanem globalnym. @MainMa ma kilka innych problemów, które moim zdaniem są prawidłowe, ale gorzej zdefiniowane. Jeffery Thomas wspomina o I / O i UI. Myślę, że jeśli dodasz dobre części tych trzech odpowiedzi, uzyskasz świetną spójną odpowiedź. Najbardziej podoba mi się ta odpowiedź ze względu na skupienie się na antipatternach kodu.
M2tM,
1
Argh - nic gorszego niż twierdzenia z testu jednostkowego, które nie są podobne do wymagań biznesowych i są tylko danymi wyjściowymi w danym czasie - próbami, które są na przykład wywoływane 3 razy? Dlaczego 3? Ponieważ była pierwsza, kiedy test był uruchamiany / powtarzany :)
Michael
Ciasne połączenie jest złe tylko wtedy, gdy jest nieodpowiednie. Konieczne jest ścisłe sprzężenie w kodzie, które jest bardzo spójne. Na przykład deklaracja zmiennej, po której następuje jej użycie. Mocno połączone, bardzo spójne.
dietbuddha
1
Testy jednostkowe, w których dane wyjściowe są sprawdzane pod kątem tego, co zrobił kod, bez żadnego uzasadnienia biznesowego / uzasadnienia, nazywane są testami charakterystyki. Są używane w konserwacji, gdzie wcześniej nie było testów i często nie ma udokumentowanych wymagań i musisz włożyć coś, co się zepsuje, jeśli wynik tej funkcji się zmieni. Są lepsze niż nic.
Andy Krouwel,
5

Typowe przykłady kodu, który ludzie nie chcą testować jednostkowo:

  • Kod, który bezpośrednio współdziała z operacjami we / wy (odczyt plików, bezpośrednie połączenia sieciowe,…)
  • Kod, który bezpośrednio aktualizuje interfejs użytkownika.
  • Kod, który bezpośrednio odwołuje się do singletonów lub obiektów globalnych.
  • Kod, który domyślnie zmienia stan obiektu lub podobiektu.

Za pomocą fałszywego frameworka wszystkie te przykłady mogą być testowane jednostkowo. Wystarczy skonfigurować pozorne zamienniki wewnętrznych zależności.

Rzeczy, które naprawdę nie mogą być testowane jednostkowo:

  • Nieskończone pętle (dla menedżera wątków, sterownika lub innego typu długo działającego kodu)
  • Niektóre rodzaje operacji bezpośredniego montażu (obsługiwane przez niektóre języki)
  • Kod wymagający uprzywilejowanego dostępu (nie jest to niemożliwe, po prostu nie jest to dobry pomysł)
Jeffery Thomas
źródło
2

Jest kilka obszarów, które mogą utrudnić pisanie testów jednostkowych. Chciałbym jednak podkreślić, że nie oznacza to, że należy odrzucić przydatne techniki po prostu dlatego, że mogą one zwiększyć złożoność testów. Podobnie jak w przypadku każdego kodowania , powinieneś zrobić własną analizę, aby ustalić, czy korzyści przewyższają koszty, i nie ślepo zaakceptować tego, co niektórzy przypadkowi faceci publikują w sieci.

Źle napisany zaprojektowany kod

  • niewłaściwe połączenie (zwykle ciasne połączenie tam, gdzie nie powinno być)
  • kod zlewu kuchennego (gdzie funkcja ma zbyt dużą logikę / obowiązki)

Reliance stanu w innym zakresie

Koszt większości z nich wymyka się spod kontroli, chyba że wiesz, co robisz. Niestety wielu często nie wie, jak korzystać z tych technik w celu złagodzenia takich rzeczy, jak testowanie złożoności.

  • Singletony
  • Globals
  • Zamknięcia

Stan zewnętrzny / systemowy

  • Zależności sprzęt / urządzenie
  • Zależności sieciowe
  • Zależności systemu plików
  • Zależności między procesami
  • Inne zależności wywołania systemowego

Konkurencja

  • Gwintowanie (zamki, sekcje krytyczne itp.)
  • widelec
  • Coroutines
  • Oddzwoń
  • Programy obsługi sygnałów (nie wszystkie, ale niektóre)
dietbuddha
źródło
2

Nie ma czegoś takiego jak kod, którego nie można przetestować. Istnieje jednak kilka przykładów kodu, który NAPRAWDĘ, NAPRAWDĘ trudny do przetestowania (do tego stopnia, że ​​być może nie jest wart wysiłku):

Interakcje sprzętowe - Jeśli kod bezpośrednio manipuluje sprzętem (na przykład zapis do rejestru w celu przeniesienia urządzenia fizycznego), testowanie urządzenia może być zbyt trudne lub kosztowne. Jeśli użyjesz prawdziwego sprzętu do testu, może to być drogie, aby uzyskać odpowiednią informację zwrotną do uprzęży testowej (jeszcze więcej sprzętu!), A jeśli nie, musisz naśladować dokładne zachowanie obiektów fizycznych - nie jest to mała sztuczka w niektóre przypadki.

Interakcje z zegarem - jest to zwykle łatwiejsze, ponieważ prawie zawsze można kpić z funkcji zegara systemowego całkiem trywialnie. Ale kiedy nie możesz, testy te stają się niemożliwe do zarządzania - testy oparte na czasie rzeczywistym zwykle trwają długo, a z mojego doświadczenia wynika, że ​​są bardzo kruche, ponieważ obciążenia systemu powodują, że rzeczy trwają dłużej niż powinny. , powodując niepowodzenia testu fantomowego.

Michael Kohne
źródło
0

Moje trzy główne grupy do tego to:

  • kod oparty na usługach zewnętrznych

  • systemy, które nie pozwalają testerom modyfikować stanu niezależnie od aplikacji.

  • środowiska testowe, które nie replikują konfiguracji produkcyjnej.

Tego najbardziej doświadczyłem jako programista, który został inżynierem ds. Kontroli jakości.

Michael Durrant
źródło