w , ,

FajneFajne Dobre!Dobre! ŚwietnieŚwietnie WnerwWnerw

Piramida, Diament i Trofeum – Jak Rozplanować Testy Automatyczne w Aplikacji

Piramida testów określa schemat rozłożenia testów w aplikacji. Stanowi ona pewien zbiór spostrzeżeń dotyczących testów automatycznych, które powielają się w systemach informatycznych. Z czasem piramida ewoluowała i powstawały nowe koncepcje, takie jak diament czy trofeum. W tym artykule opowiem Ci,co doprowadziło do powstania nowych koncepcji, jak się one kształtują oraz jak rozsądnie rozłożyć testy w aplikacji. Artykuł ten jest fragmentem mojej książki oraz Kursu Testowania Automatycznego Dla Java Developerów W Praktyce.

Piramida testów

Jej wizualizacji jest wiele – warto o tym pamiętać, bo w każdej chwili może przybiec świeżo upieczony tester trzymający w ręku certyfikat ISTQB i powie, że w jego świecie wygląda to inaczej 🙃. Jednak, z punktu widzenia Backend Developera, najbardziej rozsądny schemat rozkłada się pomiędzy trzy poziomy testów:

  • jednostkowe
  • integracyjne
  • End-to-End (E2E).

Im niższy poziom piramidy, tym więcej danych testów „powinno” występować w aplikacji. Głównymi czynnikami determinującymi tę zależność są:

  • szybkość wykonywania się – czas uruchomienia testów jednostkowych to zazwyczaj kilka sekund per test, każdy następny poziom to zazwyczaj kilkukrotnie dłuższy czas oczekiwania.
  • czas reakcji – im niższego poziomu jest test, tym szybciej dostajemy informację o błędzie. Dzięki temu jesteśmy ciągle w temacie, mamy w głowie ostatnie działanie i jesteśmy w stanie taniej i łatwiej to naprawić.
  • wystarczalność – jeśli daną funkcjonalność można pokryć niższym poziomem testów, to nie ma potrzeby strzelać z armaty do wróbla.

Zależność jest taka, że każdy test niższego poziomu można zastąpić testem wyższego poziomu. Jednak nie każdy test wyższego poziomu można zastąpić testem niższego poziomu. Więc finalnie w aplikacji można zastąpić wszystkie testy jednostkowe testami E2E. Ale to tylko zależność, więc nie próbuj jej praktykować 😆.

Testy jednostkowe w testowaniu automatycznym

Wykonują się bardzo szybko. Każdy developer może uruchomić je na swojej maszynie i w kilka sekund dostać rezultat. Do ich wykonania zazwyczaj nie potrzeba uruchomienia czy też posiadania specjalnej infrastruktury. Zazwyczaj wystarczy samo IDE, dlatego też są uważane za tanie i szybkie.

Ich głównym zadaniem jest sprawdzenie wykonywania poprawności danej funkcjonalności i zawsze powinniśmy je pisać w oparciu o założenia projektowe. Dodatkowym wyznacznikiem, który ma znaczenie przy testach, jest stan pokrycia kodu testami, czyli coverage. W idealnym świecie powinien on wynosić 100%. Jednak dużo gorszą praktyką jest pisanie mało rozsądnych testów tylko po to, aby podbić ten wskaźnik. Jest to jeden z dwóch czynników, o których wspominam na kursie testów automatycznych, które prowadzą do betonowania kodu.

Testy integracyjne w testowaniu automatycznym

Dość kosztowe, głównie z tego względu, że wymagają złożonej infrastruktury. Zazwyczaj do przeprowadzenia testów integracyjnych musimy zaangażować inne komponenty, serwisy lub bazy danych.

Dobrą praktyką jest, by na potrzeby testów integracyjnych tworzyć profile aplikacji, tak aby uruchamiane skrypty nie zaszkodziły bazie danych/komponentom, które działają na produkcji lub innym środowisku.

Zdarza się, że developer nie ma w pełni skonfigurowanego środowiska (z braku czasu lub skomplikowania systemu, bo przecież nie z lenistwa 🙂) do uruchomienia testów integracjach i rezultat ich wykonania otrzymuje po kilkudziesięciu minutach, po tym jak zostaną one przetworzone przez Continuous Integration.

Jak widzisz, potrzeba dobrej (i kosztownej) infrastruktury, aby można było rozsądnie wykonywać ten rodzaj testów. Jednak praktyczna praca z nimi dostarcza dużo frajdy, bo wymagają przemyślenia budowy profili, tworzenia skryptów migracyjnych i wersjonowania ich na potrzeby baz danych oraz podjęcia wielu innych działań – dlatego dla mnie są one bezkompromisowo najciekawsze 🙂

Fragment z implementacji testów integracyjnych z mojego szkolenia pozostawiłem na swoim kanale do wglądu:

Testy End To End w testowaniu automatycznym

Są najbardziej kosztowe i czasochłonne, ponieważ wymagają uruchomienia całego serwera, backendu, frontendu, bazy danych i zapewnienia całej komunikacji między wszystkimi elementami. Oczywiście jeśli mowa tutaj o prostym modelu aplikacji monologicznej.

Dlatego im bardziej zaawansowany system, tym trudniej wykonać taki test. Za głowę idzie się złapać, jeśli mamy świat mikroserwisów (chociaż tam bardziej dominują testy integracyjne, o czym za chwile).

Do ich implementacji bardzo często stosuje się biblioteki frontendowe. Java posiada swój zestaw, ale sam stosuje Cypres, która jest bardzo wygodną biblioteką JS. Pozwala na pobranie znaczników HTML oraz symulowanie działań dokładnie tak, jakby wykonywał je użytkownik.

Można uruchomić ją w ramach Continuous Integration i otrzymać rezultat wykonanych testów w postaci tekstowej, lub też uruchomić lokalnie (po postawieniu pełnej infrastruktury u siebie, oczywiście 😉) a następnie śledzić rezultat – co po kolei zostało kliknięte przez bota 🙂

Odpowiedzialność w testach automatycznych
Odpowiedzialność testów automatycznych

Piramida testów vs trofeum i diament

W ostatnim czasie coraz częściej pojawiają się środowiska mikroserwisów. Tam kontrakty i testy integracyjne odgrywają bardzo ważną rolę. Uwzględniają mnogość mikroserwisów, a stosunkowo niewielka ilość funkcjonalności w każdym z nich doprowadza do przekształcenia piramidy, gdzie to testów integracyjnych robi się najwięcej. Wówczas model piramidy zamienia się na kształt diamentu.

Można pójść dalej i w świecie frontendu przyjrzeć się Angularowi. Tam testami integracyjnymi są testy, które obejmują więcej niż jeden komponent. Z tego samego powodu piramida zostanie zaburzona, również przyjmując kształt diamentu. Gdy ten diament osadzić na podeście – wówczas otrzymujemy trofeum! Natomiast nasz podest to nic innego jak statyczna analiza kodu, która w pewnym stopniu stanowi alternatywę (chociaż dla mnie bardziej uzupełnienie) samych testów.

Każda z tych koncepcji jest jedynie graficznym odwzorowaniem dostrzeganych tendencji w różnych projektach. Nie stanowią one standardów czy najlepszych praktyk. W zależności od systemu te podejścia mogą być zupełnie różne.

Testy Automatyczne – podsumowanie

Na koniec szybki zbiór odpowiedzialności każdego z testów.

Testy jednostkowe:

  • Przede wszystkim funkcjonalności, nigdy nie piszemy ich separatywnie od wymagań biznesowych.
  • Testujemy nimi poprawność wykonywania funkcjonalności, a także algorytmów w przypadku klas utilowych.

Testy integracyjne

  • Testujemy to, czego nie możemy jednostkowo czyli np:
    • Sprawdzamy rezultat wykonywania operacji z bazą danych lub innym serwisem/komponentem.
    • Sprawdzamy obsługę błędów. Czy jeśli np. przekażemy niewłaściwe dane do kontrolera, to czy otrzymamy w rezultacie odpowiedni status/kod błędu.

Testy End-to-End (E2E)

Symulacja krok po kroku dokładnie tego, co wykonuje użytkownik. Używając ich, tworzymy najbardziej krytyczne z punktu widzenia biznesowego scenariusze. Przykładowo, jeśli mamy aplikację typu booking.com, to sprawdzamy, czy da się wyszukać hotel w centrum warszawy z miejscem parkingowym. Uwzględniamy najważniejsze dla nas przypadki, bez działania których aplikacja nie przedstawia sobą żadnej wartości.

Testy automatyczne w praktyce

A jeśli chcesz nauczyć się tego wszystkiego w praktyce, to jeszcze raz zapraszam Cię na TestowanieAutomatyczne.pl.

Napisane przez Przemysław Bykowski

Aktywny programista i energiczny trener. Specjalizuje się w Spring Boot i uczę go w ramach AkademiaSpring.pl. Po godzinach udzielam się na YouTubach. Więcej o mnie.

Dodaj komentarz

Co musi umieć Java Developer

Co musi umieć Java Developer w 2021? Oto wymagania stawiane kandydatom

testy jednostkowe, testy integracyjne, testy end to end

Testy integracyjne – najlepsze praktyki w 3 krokach