Scroll to top
en pl

Jakie powinny być testy


Mateusz Olczak - 10 października 2019 - 0 comments

W poprzednim artykule odpowiadaliśmy na pytanie dlaczego warto pisać testy. Okazuje się, że dobrze dobrane i odpowiednio zastosowane testy mają rzeczywisty wpływ na zmniejszenie liczby błędów i prawidłowe wykonywanie się kodu, a także znacząco ułatwiają, a czasami nawet przyspieszają pracę programisty. Pojawiają się jednak kolejne pytania – jak pisać testy, żeby osiągnąć jak najlepszy efekt? Jak dopasować stopień pokrycia kodu testami i rodzaj testów do potrzeb konkretnego projektu?

Zasada FIRST

Prawidłowo przygotowane testy, które pokrywają odpowiednio dużą część kodu, faktycznie zabezpieczają projekt przed zagrożeniem związanym ze zmianami. Jest to najbardziej efektywne, gdy projekt posiada odpowiednią strukturę i programista korzysta ze wsparcia IDE – w takim przypadku najbardziej kluczowe moduły można szybko i bezproblemowo pokryć testami.

Charakter testów najlepiej definiuje zasada FIRST. Zgodnie z tymi wytycznymi testy powinny być szybkie (Fast), niezależne (Isolated), powtarzalne (Repeatable), samosprawdzające (Self-validating) i kompletne (Thorough).

Przyjrzyjmy się bliżej poszczególnym cechom, którymi powinny charakteryzować się dobrze napisane testy.

F (fast) – szybkie

Nikt nie lubi długo czekać na załadowanie się strony, uruchomienie animacji czy zbudowanie programu. Dla programisty nie ma nic gorszego niż wolno działające narzędzia. Podobnie jest z testami. Czas wykonywania testów nie powinien zniechęcać do ich uruchamiania. Podczas pisania testów należy pamiętać o tym, że długi czas ich wykonywania zwiększa czas budowania całej paczki. Dlatego wprowadzenie wolnych testów, o długim czasie wykonywania skutkuje zmniejszeniem częstotliwości ich uruchamiania. Z czasem konsekwencją tego może być nawet całkowite zaniechanie uruchamiania testów.

I (isolated) – niezależne

Każdy test powinien sprawdzać tylko jeden, konkretny przypadek. Oznacza to, że każda metoda lub nawet poszczególne jej części powinny być testowane oddzielną asercją, zawierającą specyficzne dane. Jeden test nie może być powiązany z innymi ani nie powinien na nie wpływać. Jest to istotne zwłaszcza w kontekście utrzymania i rozwoju kodu – dzięki takiemu rozplanowaniu testów można swobodnie rozbudowywać poszczególne moduły lub dodawać nowe. Niezależność testów sprawia, że nie mają one wpływu na środowisko testowe, a kolejność ich wykonywania nie powinna mieć znaczenia dla działania całego programu.

R (repeatable) – powtarzalne

Tylko powtarzalność testów sprawia, że są one miarodajne i świadczą o prawidłowym działaniu programu. Jest to jeden z głównych aspektów, który daje przewagę nad testami manualnymi. Testy powinny zwracać ten sam wynik niezależnie od środowiska, w którym są uruchamiane, klasy sprzętu maszyny, na której są wykonywane, specyficznych ustawień środowiska czy czasu ich wykonywania.

Problemy z powtarzalnością wykonania testów mogą wskazywać na problemy w samym kodzie produkcyjnym. Dane testowe powinny być z góry określone, z wyłączeniem przypadków, gdy nie chcemy sprawdzać zachowań programu dla określonych danych, a jedynie dla pewnego zakresu, np. zdefiniowanego poprzez typ (np. Intetger).

S (self-validating) – samosprawdzające

Głównym założeniem testowania programu jest ułatwienie lokalizacji błędów, co przyspiesza proces ich naprawy. Właśnie dlatego wynik testu powinien być widoczny na pierwszy rzut oka, bez konieczności wnikliwego sprawdzania przypadku i testowanego obszaru. Aby zachować czytelność i przejrzystość w przeprowadzaniu testów, informacje o sprawdzanym obszarze powinny być zawarte w nazwie metody testujące, a sam test powinien sprawdzać jedno założenie. W ten sposób programista może szybko zorientować się czego dotyczy dany test i jaki jest jego wynik.

T (thorough) – kompletne

Testy powinny być niezależne, co nie oznacza jednak, że nie powinny sprawdzać znacznego obszaru kodu. Duże pokrycie testami przekłada się na zwiększone zaufanie do aplikacji. Aby podnieść jakość programu i jednocześnie potwierdzić jego niezawodność, dobrane testy powinny być jak najbardziej różnorodne. Istotne są zarówno testy sprawdzające warunki brzegowe, testy rzucania wyjątków, testy z wykorzystaniem dużych zbiorów danych, jak i testy z użyciem danych wejściowych, które teoretycznie nigdy nie powinny zostać wprowadzone przez użytkownika.

Rodzaje testów

Wśród testów oprogramowania wyróżnić można trzy główne grupy testów, kategoryzujące testy pod względem sprawdzanego zakresu – jednostkowe, integracyjne i E2E (End-to-end). Testy E2E to testy najbardziej globalne, sprawdzające złożone funkcjonalności programu lub funkcje interfejsu użytkownika. Testy integracyjne sprawdzają spójność i współpracę poszczególnych modułów, włączając w to zewnętrzne usługi i aplikacje, natomiast zadaniem testów jednostkowych jest testowanie prawidłowości najmniejszych fragmentów kodu, bez oceniania ich zachowania w kontekście całego programu.

Testy w aplikacji

Dobór rodzaju i liczby testów to zawsze spore wyzwanie, zwłaszcza w przypadku bardzo kompleksowych projektów. Złożone aplikacje z rozbudowaną logiką biznesową wymagają zastosowania wielu testów jednostkowych, które pomogą szybko wykryć ewentualne błędy w algorytmach. W tej sytuacji drugie miejsce zajmują testy integracyjne, natomiast najmniej praktyczne są tutaj testy manualne i np. selenium, ze względu na czas wykonywania oraz czas potrzebny na przygotowanie tego typu testów.

Niedawno w sieci pojawiły się opinie twórców portali społecznościowych, według których testy jednostkowe nie są potrzebne. Jest to dosyć kontrowersyjne stwierdzenie, szczególnie biorąc pod uwagę ostatnie kilka lat rozwoju branży IT oraz literaturę fachową, w której jednoznacznie określono, że bez testów jednostkowych nie można w ogóle mówić o czystości kodu. Stwierdzenie które padło z ust twórców portali społecznościowych może być prawdą, ale tylko w pewnych, określonych sytuacjach. 

W przypadku aplikacji opartych głównie na interfejsie, w których logika biznesowa oraz złożone algorytmy nie są istotnymi komponentami, można mówić o odwróconej piramidzie, która określa liczbę testów danego rodzaju. W aplikacjach tego typu najważniejsze są testy “końcowego użytkownika”.

To co najważniejsze w testach

Testowanie programu to bardzo odpowiedzialne zadanie. Właściwy dobór testów do potrzeb projektu oraz pisanie ich zgodnie z zasadami czystości kodu ma rzeczywisty wpływ na szybkość i efektywność pracy programistów. Błędy zdarzają się każdemu, a testy pozwalają na łatwe wykrycie pomyłek, tym samym skracając proces naprawy kodu i eliminując ryzyko wprowadzenia na rynek programu wątpliwej jakości. 

Related posts