Czy potrzebuję testu jednostkowego, jeśli mam już test integracyjny?

47

Jeśli mam już test integracyjny dla mojego programu i wszystkie zdały pomyślnie, to mam wrażenie, że zadziała. Jakie są zatem powody, aby pisać / dodawać testy jednostkowe? Ponieważ i tak muszę już pisać testy integracyjne, chciałbym napisać tylko test jednostkowy dla części, które nie są objęte testami integracyjnymi.

To, co znam, to przewaga testu jednostkowego nad testem integracyjnym

  • Mały, a zatem szybki do uruchomienia (ale dodanie nowej jednostki w celu przetestowania czegoś jest już testowane przez test integracyjny, oznacza to, że mój komplet testowy staje się większy i dłuższy do uruchomienia)
  • Łatwiej zlokalizuj błąd, ponieważ testuje tylko jedną rzecz (ale mogę rozpocząć test jednostkowy, aby zweryfikować każdą poszczególną część, gdy mój test integracji nie powiódł się)
  • Znajdź błąd, który może nie zostać wykryty w teście integracji. np. błędy maskowania / kompensacji. (ale jeśli moje testy integracyjne przebiegną pomyślnie, co oznacza, że ​​mój program będzie działał, nawet istnieje jakiś ukryty błąd. Więc znajdź / napraw te błędy nie mają tak naprawdę wysokiego priorytetu, chyba że zaczną przerywać przyszłe testy integracyjne lub powodować problemy z wydajnością)

I zawsze chcemy pisać mniej kodu, ale testy jednostkowe zapisu wymagają dużo więcej kodu (głównie próbnych obiektów konfiguracji). Różnica między niektórymi moimi testami jednostkowymi a testami integracyjnymi polega na tym, że w testach jednostkowych używam próbnego obiektu, aw testach integracyjnych używam rzeczywistego obiektu. Które mają dużo duplikacji i nie podoba mi się powielony kod, nawet w testach, ponieważ to dodaje narzut, aby zmienić zachowanie kodu (narzędzie refaktoryzacyjne nie może cały czas działać).

Bryan Chen
źródło
Po prostu z ciekawości, jaki zasięg mają twoje testy integracyjne? Ponadto, jeśli masz złożoną logikę, czy testy integracyjne obejmują je wszystkie, czy tylko ich część i które części są ważne dla biznesu lub losowo?
civan 12.04.17
To pytanie wydaje się dwuznaczne. Załóżmy, że mam metodę kontrolera Rails, która wywołuje interactor ( github.com/collectiveidea/interactor ). Zdecydowałem się napisać testy integracji dla mojej metody kontrolera (ponieważ bez nich nie mogę ufać, że mój punkt końcowy interfejsu API działa). Istnieją tutaj co najmniej dwa pytania: (1) czy powinienem również napisać testy jednostkowe dla moich metod kontrolera (tj. Czy powinienem napisać testy jednostkowe, które sprawdzają to samo zachowanie, co moje testy integracyjne), oraz (2) powinienem również napisać testy jednostkowe dla mojego interaktora? Odpowiedziałbym na te dwa pytania inaczej w niektórych kontekstach biznesowych.
Daniel

Odpowiedzi:

33

Przedstawiłeś dobre argumenty za i przeciw testom jednostkowym. Musisz więc zadać sobie pytanie: Czy dostrzegam wartość argumentów pozytywnych, które przewyższają koszty argumentów negatywnych? Z pewnością:

  • Małe i szybkie to niezły aspekt testów jednostkowych, choć w żadnym wypadku nie najważniejszy.
  • Łatwiejsze lokalizowanie błędów [s] jest niezwykle cenne. Wiele badań dotyczących profesjonalnego tworzenia oprogramowania wykazało, że koszt błędu rośnie gwałtownie w miarę starzenia się i przesuwania się w dół w kierunku dostarczania oprogramowania.
  • Znalezienie maskowanych błędów jest cenne. Gdy wiesz, że wszystkie komponenty mają sprawdzone wszystkie swoje zachowania, możesz z pewnością korzystać z nich w sposób, w jaki nie były wcześniej używane. Jeśli jedyną weryfikacją jest testowanie integracyjne, wiesz tylko, że jego bieżące zastosowania działają poprawnie.
  • Kpiny są kosztowne w rzeczywistych przypadkach, a utrzymywanie kpin jest podwójnie. W rzeczywistości, kpiąc z „interesujących” obiektów lub interfejsów, możesz potrzebować nawet testów, które sprawdzą, czy twoje fałszywe obiekty poprawnie modelują twoje prawdziwe obiekty!

W mojej książce zalety przewyższają wady.

Ross Patterson
źródło
2
Czy kpiny nie są tańsze w rzeczywistych przypadkach? Ustawiasz tylko oczekiwania dotyczące wiadomości otrzymywanych przez próbkę i określasz, co ona zwróci.
Dogweather
10
@Dogweather Mocks działają dobrze po pierwszym utworzeniu. W miarę upływu czasu i zmiany prawdziwego obiektu, drwiny muszą się z nim zmieniać. 10 lat i 6000 testów jednostkowych, bardzo trudno jest wiedzieć, że twoje „udane” testy są naprawdę udane.
Ross Patterson
1
Poza tym, że „10 lat i 6000 testów jednostkowych” to liczby z własnego doświadczenia, a nie hiperbola.
Ross Patterson
3
Zacząłem pisać zautomatyzowane testy programistyczne (jednostka i integracja, ale głównie te ostatnie) już w 2004 lub 2005 r. I opracowałem zaawansowaną bibliotekę próbną dla Javy. Wiele razy widziałem wiele testów integracyjnych zrywających się z tego samego powodu (jak zmiana DB lub zmiana sieci) i czasami piszę testy integracyjne „niższego poziomu” dla komponentów wielokrotnego użytku, ale nadal wolę mieć tylko testy integracyjne. Pojedyncze testy jednostkowe z kpiną przez większość czasu po prostu nie są tego warte; Szyderstwa stosuję wyłącznie jako pomoc w testach integracyjnych.
Rogério,
Twój ostatni punkt wydaje się być sprzeczny z twoją argumentacją. W tym punkcie wypowiadasz się przeciwko pisaniu niepotrzebnych prób, co jest argumentem przeciwko pisaniu testów jednostkowych dla części, które są już objęte testami integracyjnymi. Argumentacja przemawia jednak na korzyść pisania testów jednostkowych dla części, które są już objęte testami integracyjnymi. Czy mógłbyś wyjaśnić tutaj swój zamiar @RossPatterson?
Daniel
8

Nie widzę większej wartości w ponownym wdrażaniu istniejącej skrzynki testowej integracji jako niesprawiedliwej.

Testy integracyjne są często o wiele łatwiejsze do napisania dla starszych aplikacji, ponieważ zwykle funkcje, które mają być testowane, są ściśle ze sobą powiązane, więc jednostki testowe w izolacji (= niekwestionowanie) mogą być trudne / kosztowne / niemożliwe.

> Then what are the reasons to write/add unit tests?

Moim zdaniem rozwój oparty na testach jest najskuteczniejszy, jeśli napiszesz testy jednostkowe przed właściwym kodem. W ten sposób kod, który spełnia testy, zostaje wyraźnie oddzielony przy pomocy minimum zewnętrznych odnośników, które można łatwo przetestować.

Jeśli kod już istnieje bez testów jednostkowych, zwykle jest dużo pracy, aby napisać testy jednostkowe później, ponieważ kod nie został napisany dla łatwego testowania.

Jeśli wykonasz TDD, kod będzie można łatwo przetestować.

k3b
źródło
2
Jeśli mam starszą aplikację bez unit-testsi chcę dołączyć unit-testsdo niektórych części, czy uważasz, że lepiej jest najpierw napisać integration testsdla starszego kodu. Kiedy to zostanie napisane, możesz rozłączyć ścisłe połączenie i stworzyć funkcje z interfejsami, które można przetestować? Skoro masz integration-testjuż napisane, możesz następnie sprawdzić na każdym etapie refaktoryzacji, czy nowa wersja kodu nadal działa zgodnie z oczekiwaniami?
alpha_989
2
@ alpha_989, to jest bardzo IMHO i jestem otwarty na inne pomysły, ale wolę testy integracyjne niż testy jednostkowe starszego kodu. W obu przypadkach musisz mieć pewność, że metody działają poprawnie przed dodaniem jakiegokolwiek rodzaju testowania, ale testowanie integracyjne zapewnia, że ​​ogólne oczekiwania metod działają w przeciwieństwie do poszczególnych elementów kodu.
Britt Wescott
5

Testy integracyjne powinny jedynie weryfikować, czy kilka komponentów współpracuje zgodnie z oczekiwaniami. To, czy logika poszczególnych elementów jest dokładna, należy zweryfikować za pomocą testów jednostkowych.
Większość metod ma kilka możliwych ścieżek wykonania; pomyśl o zmiennych typu if-then-else, zmiennych wejściowych o nieoczekiwanych lub po prostu błędnych wartościach itp. Zwykle programiści myślą tylko o szczęśliwej ścieżce: normalnej ścieżce, która nie idzie źle. Ale jeśli chodzi o te inne ścieżki, masz dwie opcje: możesz pozwolić użytkownikowi końcowemu na zbadanie tych ścieżek poprzez działania podejmowane w interfejsie użytkownika i mieć nadzieję, że nie spowodują one awarii aplikacji, lub możesz napisać testy jednostkowe, które potwierdzają zachowanie tych innych ścieżek i podejmowanie działań w razie potrzeby.

Stefan Billiet
źródło
4

Niektóre z powodów, które wskazałeś w swoim pytaniu, są naprawdę ważne i same w sobie mogą przemawiać za testami jednostkowymi, ale YMMV. Na przykład, jak często uruchamiasz zintegrowany zestaw testów? Moje doświadczenie ze zintegrowanymi testami jest takie, że prędzej czy później będą one tak wolne, że nie będziesz ich uruchamiał za każdym razem, gdy wprowadzasz zmiany, a czas między wstawieniem a wykryciem błędu wydłuży się.

Dużym błędem, który możesz popełnić, jest zaufanie

Find bug that may not be caught in integration test. e.g. masking/offsetting bugs.

to nie ważne. Czy spodziewasz się, że Twoi użytkownicy znajdą dla Ciebie błędy? Ufanie pokryciom uzyskanym ze zintegrowanych testów jest moim zdaniem niebezpieczne, możesz bardzo łatwo uzyskać wysoki procent pokrycia, ale w rzeczywistości testujesz bardzo mało.

Sądzę, że kanonicznym odniesieniem do zintegrowanych testów są posty JBrain:

http://www.jbrains.ca/permalink/integrated-tests-are-a-scam-part-1

na wypadek, gdybyś ich jeszcze nie przeczytał.

Wreszcie, IMO opinie, które można uzyskać z testów jednostkowych dla twojego projektu, są nieocenione. Błędem może być również osądzanie projektu na podstawie intuicji i poleganie na zintegrowanych testach.

José Ricardo
źródło
Tak naprawdę nie rozumiem tego artykułu. Istnieje więc wiele ścieżek kodu, a testy integracyjne nie są w stanie objąć ich wszystkich ... więc? To samo dotyczy testów jednostkowych, chyba że twoje jednostki są tak trywialne, że są bezcelowe.
Casey,
To bardziej jak argument przeciwko naprawianiu pokrycia kodu w ogóle niż taki, że powinieneś pisać mnóstwo testów jednostkowych i unikać testów integracyjnych.
Casey
1

Jeśli kiedykolwiek będziesz musiał modyfikować lub refaktoryzować kod, niezbędne są testy jednostkowe. Testy jednostkowe istnieją nie tylko w celu wykazania błędów w momencie pisania kodu, ale także w celu pokazania, kiedy pojawiają się nowe błędy, gdy więcej kodu zostanie napisane.

Tak, dużo lepiej jest najpierw napisać testy integracyjne i jednostkowe, ale ich posiadanie ma dużą wartość, nawet jeśli zostaną napisane później.

Matthew Flynn
źródło
3
Nie wydaje mi się, żebyś to zrobił. Testy integracyjne ujawniłyby również błędy w kodzie i faktycznie są w stanie wyłapać błędy, których nie wykryją testy jednostkowe.
Casey