Testowanie aplikacji. Porównanie testów jednostkowych i integracyjnch.

Testy, testy i jeszcze raz testy, każdy o nich mówi niestety nie każdy pisze. Sam staram się wyrobić w sobie od początku wędrówki dobry nawyk testowania nowych funkcjonalności. Zanim jednak do tego doszło musiałem sobie odpowiedzieć na jedno … , ale to … ważne pytanie: po co testować aplikację?

Z własnego lenistwa

Tak bym Ci odpowiedział. A dlaczego? Bo oszczędzisz sporo czasu. Załóżmy, że napisałeś kod w którym wszystko jest dla Ciebie jasne, musisz podzielić x przez y, dodać 21.65 i z tego wszystkiego pierwiastek (nie wnikajmy w sens, dla przykładu tak ma być). Dokładnie wiesz dlaczego tak, a nie inaczej.

Pokuśmy się o kolejne założenie, nie napisałeś testów i wracasz do powyższego kodu po miesiącu. Nie zrobiłeś komentarzy – przecież wszystko było jasne. Teraz drapiesz się po głowie i za nic nie wiesz dlaczego to przestało działać i gdzie jest pies pogrzebany, nie wiesz nawet o co w tym chodziło.

Testy mogłyby w tym przypadku pomóc drogi czytelniku. Popatrz, a co gdybyś miesiąc wcześniej naskrobał kilka testów jednostkowych do pojedynczych metod?

Niekiedy już samo czytanie testów mówi nam jak coś ma działać i dlaczego. Wpisujesz szczęśliwy dotnet test / ctrl+ R + A  i jak na dłoni widzisz gdzie jest byk! Oszczędziłeś swój czas, pot wytarty z czoła i usta od cichych przekleństw pod nosem.

Test Driven Development

Mówiąc o testach ciężko pominąć temat TDD i nie jest to bynajmniej siostra kreskówkowego Dextera. TDD to dokładniej zwinna metoda wytwarzania oprogramowania. W wielkim uproszczeniu polegającą na jednoczesnym pisaniu testów i funkcjonalności. Cały proces dobrze obrazuje poniższy graf.

Ścieżka którą będziemy się poruszać w procesie wytwarzania oprogramowania pod ręką z TDD to Red, Green, Refactor (nie pomyl kolorków, a zajdziesz daleko 🙂

  • Piszemy testy sprawdzające funkcjonalność (testy niespełnione – RED)
  • Implementujemy funkcjonalność (spełniamy wcześniej napisany test – Green)
  • Refaktoryzujemy napisany kod (testy nie są spełnione – Refactor)

Cykl powtarzamy do uzyskania efektu satysfakcjonującego klienta i nas, czasem może to być długotrwały i żmudny proces. Jak mawiał mój kolega:

Efekt połysku uzyskujemy długotrwałym procesem polerowania.

Świat TDD rządzi się swoimi prawami. Znalazło się w nim miejsce dla kilku rodzajów testów, dwa z nich o których chciałbym Ci opowiedzieć to:

Testy jednostkowe

Sprawdzają czy pojedyncza część kodu działa poprawnie. Po dostarczeniu danych wejściowych sprawdzamy czy rezultat testowanego kodu jest zgodny z naszymi oczekiwaniami. W sytuacjach gdy sama implementacja rozwiązania może być dla nas niezrozumiała, testy jednostkowe są pomocne w zrozumieniu intencji programisty.

W testach jednostkowych zależności (np. logowanie do bazy danych) powinny być zasymulowane, zastąpione przy wykorzystaniu bibliotek mockujących (Mock). Użycie biblioteki Moq zaprezentuję w kolejnym wpisie (i liczę na to, że go przeczytasz!).

Testy integracyjne

Sprawdzają czy różne części aplikacji działają poprawnie. W przeciwieństwie do testów jednostkowych, testy integracyjne często dotyczą problemów związanych z infrastrukturą aplikacji np. bazą danych, systemem plików, zasobami sieciowymi czy żądaniami i odpowiedziami sieciowymi.

Testy integracyjne wykonują większe segmenty kodu, opierają się na elementach infrastruktury aplikacji – są wolniejsze niż testy jednostkowe (ale równie potrzebne).
Warto ograniczyć liczbę testów integracyjnych, szczególnie jeśli to samo można przetestować za pomocą testów jednostkowych.

Konfrontacja

W poniższej tabeli przedstawiam Ci różnice pomiędzy wcześniej omówionymi testami które zauważyłem, jest coś o czym nie wiem powiadom mnie koniecznie – wiedzy nigdy dość.

 

Testy jednostkoweTesty integracyjne
Testują pojedynczy element (klasę, metodę) w izolacji od pozostałych.Testują większe moduły naszego kodu (ich współpracę ze sobą).
Działają bardzo szybko.Mogą trwać długo (np. dostęp do bazy danych).
Niepowodzenia oznacza zazwyczaj jedno miejsce do naprawy.Niepowodzenie może oznaczać wiele miejsc wymagających naprawy.
Nie potrzeba dodatkowej konfiguracji przed uruchomieniem. Powinny działać na każdym urządzeniu tak samo.Dodatkowa konfiguracja może być konieczna przed uruchomieniem testów.

 

Podsumowując

Jeśli pewne zachowanie można przetestować za pomocą testu jednostkowego lub testu integracyjnego, należy wybrać test jednostkowy, ponieważ prawie zawsze będzie on szybszy.

W naszych aplikacjach możemy mieć dziesiątki lub setki testów jednostkowych, ale tylko kilka testów integracyjnych obejmujących najważniejsze scenariusze.

Dodam, że działające testy jednostkowe nie załatwiają roboty. Spójrz na tej gif

Pozdrawiam Wojtek