O TDD i BDD słów kilka. Czy warto pisać testy?

20.11.2017 AUTOR: Adam Matysiak

Musimy przyznać szczerze – żaden programista nie lubi pisać testów. Zajmują dużo czasu, ciężko się je pisze, ciągle trzeba je poprawiać, bo zmienia się kod, na koniec projektu kompletnie je porzucamy, bo nie zdążymy przed deadlinem czy dlatego, że nikt nam nie zapłaci i tak za pisanie testów.

To kilka z modelowych wymówek, choć jest ich znacznie więcej. Chciałbym jednak postawić pytanie: czy stać nas na NIE pisanie testów? Skoro wiemy jakie stwarzają one problemy, zastanówmy się wpierw czy faktycznie warto pisać testy i jakie mają zalety.

Czemu warto pisać testy?

Pewność

Najważniejsza rzecz w tym zestawieniu – jak możemy być pewni, że nasz kod działa poprawnie, jak nie będziemy przeprowadzać testów czy działa? Oczywiście możemy to robić ręcznie i tak to teraz robimy, ale czy będziemy przeprowadzać testy każdej funkcjonalności po każdej zmianie w systemie? No właśnie. Jedynie odpalenie automatycznych testów da nam jakąkolwiek pewność czy nasz kod działa według założeń.

A jak dużą pewność będziemy mieli dzięki testom to już zależy od tego jak dużo testów napiszemy. I zamiast skupiać się na dążeniu w pokryciu kodu (ang. Code coverage) do 100%, skupmy się na odzwierciedleniu funkcjonalności, zarówno na poziomie jednostkowym (klasy), jak i funkcjonalnym (cały system).

Refaktoring

Wszyscy możemy się zgodzić, że refaktoring kodu jest niezbędnym krokiem, by był czysty, przejrzysty i profesjonalny. Problem się pojawia w momencie, gdy chcemy zrobić większy refaktoring, bo zauważamy możliwość wprowadzenia wzorca projektowego albo chcemy uprościć funkcję/obiekt, która wykorzystywana jest w wielu innych miejscach.

Po każdej takiej zmianie musielibyśmy sprawdzać ręcznie cały system czy działa tak jak poprzednio, co jest oczywiście bardzo czasochłonne. Co gorsza, a niestety wielce prawdopodobne, nie wszystko pójdzie zgodnie z planem i wtedy poświęcimy dużo czasu na znalezienie nowo wprowadzonego błędu do kodu.

Zmiany w projekcie

Kolejną bardzo prawdopodobną kwestią jest wystąpienie zmian w projekcie. Jeśli projekt będzie rozwijany to na pewno zajdzie potrzeba dodania nowej funkcjonalności, modyfikacji starej, a nawet jej usunięcie. Znowu pojawia się pytanie o naszą pewność – czy wprowadzenie zmiany w kodzie nie spowoduje problemów w innym miejscu?

Myślę, że każdy z nas był w projekcie, w którym im więcej robiło się poprawek, tym więcej pojawiało się kolejnych błędów. Takie doświadczenia są wielce czasochłonne i frustrujące. Dlatego lepiej ich uniknąć.

Dokumentacja

Ostatnią kwestią, ale również bardzo ważną, jest fakt, że nasze testy są doskonałą dokumentacją systemu. Dzięki nim zobaczymy jak dana klasa działa, co zwraca; jak działa system; jakie funkcjonalności były zaimplementowane. Taka dokumentacja jest niezmiernie przydatna, gdy wrócimy do projektu po paru miesiącach.

Jakie testy pisać?

Skoro już stwierdziliśmy jakie zalety dają automatyczne testy, zapewne wszyscy dojdziemy do wniosku, że czas zacząć je pisać. Słusznie! Tylko jak zacząć?

Jak zwykle odpowiedź brzmi: to zależy :). Przede wszystkim testy możemy podzielić na:

  • jednostkowe (ang. Unit tests) – testują kod poprzez wykonywanie testów weryfikujących poprawność działania obiektów/modułów/systemów
    biblioteki jak PHPUnit, JUnit itp.
  • funkcjonalne/akceptacyjne (ang. Functional tests) – sprawdzające czy system działa poprawnie na zasadzie czarnej skrzynki (ang. black-box)
  • przeglądarkowe – m.in. Selenium, Laravel Dusk – testują zachowanie systemu poprzez odpalenie go w przeglądarce i testy na prawdziwej stronie
  • behawioralne – m.in. Cucumber, Behat, Jasmine, phpSpec – testują zachowanie obiektu poprzez definiowanie jego funkcjonalności
  • wydajnościowe (ang. Performance tests) – testujące wydajność systemu przy dużych obciążeniach

Na podstawie pierwszych dwóch klas tych testów bazują dwie obecnie najpopularniejsze metodologie, które pokrótce omówimy.

 

TDD (Test-Driven Development)

Metodologia wchodząca w skład innej metodologii XP (Extreme Programming), która stanowi dobry punkt startowy do rozpoczęcia przygodów z testami. Polega na pisaniu kodu w dość osobliwym cyklu:

1. Napisz test
2. Sprawdź czy test wykonuje się nieprawidłowo
3. Zobacz jaki jest komunikat błędu
4. Napisz kod, który naprawia ten błąd
5. Wracamy do punktu 2
6. Aż test nie wykona się prawidłowo
7. Jeśli widzimy potrzebę – dokonujemy refaktoringu i wracamy do punktu 2

To podejście, na pierwszy rzut oka, wydaje się bardzo czasochłonne, ale po nabraniu doświadczenia staje się bardzo sprawnym i wydajnym procesem, w wyniku którego powstaje tylko tyle kodu, ile jest potrzebne, by spełnić założenia testów (zasada YAGNI – You aren’t gonna need it).

BDD ( Behavior-Driven Development)

Metodologia wywodząca się z TDD, ale łącząca również DDD (Domain Driven Development) i skupiająca się na obiektowości.

Cykl pisania testów jest taki sam, natomiast co różni BDD od TDD to sposób pisania testów. W tradycyjnych testach jednostkowych możemy napisać dowolne testy, sprawdzające działanie pojedynczej funkcji, obiektu, modułu, integracji między modułami, czy systemu. Natomiast w BDD opisujemy zachowanie obiektu w stylu:

1. Scenario – nazwa scenariusza
2. Given – zakładając, że mamy…
3. When – dzieje się…
4. Then – wydarzy się…

Czyli np:
1. Scenario – kalkulator potrafi dodawać dwie liczby
2. Given – mając instancję kalkulatora
3. When – dodając 2 i 2
4. Then – zwróci 4

Dużym plusem BDD jest sposób pisania testów, który jest czytelny nawet dla osób nietechnicznych, w przeciwieństwie do testów jednostkowych, które są typowym kodem.

Podsumowanie

Omówiliśmy zatem czemu warto pisać testy i co nam dają. Wyszczególniliśmy rodzaje testów, a także podstawowe metodologie do pisania testów.

Nie odpowiedziałem natomiast na pytanie: które testy wybrać na początek? Zdecydowanie testy jednostkowe niskopoziomowe (działanie obiektu) będą dobrym wyborem. A gdy nabierzemy trochę wprawy to polecam dodać do Twojego arsenału testy wysokopoziomowe – testujące zachowanie systemu w ramach konkretnej funkcjonalności.

Testy behaworialne również są bardzo ciekawe, szczególnie pod kątem ich wykorzystania jako dokumentacji i zrozumienia przez osoby nietechniczne.

A czy można pisać testy już po napisaniu kodu? Oczywiście, że tak, ale taki kod jest znacznie trudniejszy do testowania, z większą ilością wzajemnych powiązań. Jednakże zdecydowanie lepiej mieć jakiekolwiek testy niż w ogóle. Choć zachęcam gorąco do rozpoczęcia przygody z TDD/BDD, gdyż doświadczenie w nich będzie Twoim atutem (przy staraniach o podwyżkę czy zmianie pracy), a także będziesz musiał znacznie rzadziej poprawiać swój kod :).

I ostatnia kwestia – jak się dowiedzieć więcej o testowaniu? W Internecie jest mnóstwo artykułów, prezentacji o technikach i rozwiązaniach jak testować. Ostatnio pojawia się też wiele kursów jak stworzyć konkretny system w TDD. Szczególnie polecam serwis https://laracasts.com/ dla wszystkich programistów PHP, gdzie opisane jest tworzenie forum bazując w pełni na TDD.

Powodzenia!

Artykuł powstał dzięki:

Coders Lab

Łącząc doświadczenie edukacyjne ze znajomością rynku pracy IT, Coders Lab umożliwia szybkie i efektywne zdobycie pożądanych kompetencji związanych z nowymi technologiami. Skupia się się na przekazywaniu praktycznych umiejętności, które w pierwszej kolejności są przydatne u pracodawców.

Wszystkie kursy odbywają się na bazie autorskich materiałów, takich samych niezależnie od miejsca kursu. Dzięki dbałości o jakość kursów oraz uczestnictwie w programie Career Lab, 82% z absolwentów znajduje zatrudnienie w nowym zawodzie w ciągu 3 miesięcy od zakończenia kursu.


Dlaczego nie warto bać się code review?

Do góry!

Polecane artykuły

25.06.2019

Lead scoring DMsales. Jak działa i jakie daje korzyści dla ...

Głodny wiedzy? Zapraszamy do sklepu z kursami i ebookami

Sprawdzam