Tradycyjnie, testowanie często postrzegane jest jako czynność wykonywana po zakończeniu kodowania, mająca na celu znalezienie błędów w gotowym produkcie.
Jednak nowoczesne podejścia do wytwarzania oprogramowania, szczególnie te związane z metodykami zwinnymi, odwracają tę kolejność.
Wprowadzają one koncepcję, w której testy nie tylko weryfikują gotowy kod, ale aktywnie kierują jego powstawaniem.
W tej lekcji przyjrzymy się trzem kluczowym podejściom, które traktują testowanie jako czynnik napędzający rozwój: Wytwarzaniu Sterowanemu Testami (Test-Driven Development - TDD), Wytwarzaniu Sterowanemu Testami Akceptacyjnymi (Acceptance Test-Driven Development - ATDD) oraz Wytwarzaniu Sterowanemu Zachowaniem (Behavior-Driven Development - BDD).
Zrozumienie tych koncepcji jest istotne, ponieważ stanowią one potężne narzędzia do budowania jakości od samego początku i są coraz częściej stosowane w praktyce.
Idea Testowania Napędzającego Rozwój
Wszystkie trzy podejścia – TDD, ATDD i BDD – opierają się na fundamentalnej zmianie myślenia: zamiast pisać kod, a następnie go testować, najpierw definiujemy oczekiwane zachowanie lub wynik w postaci testu, a dopiero potem piszemy minimalną ilość kodu potrzebną do spełnienia tego testu.
Ta prosta zmiana kolejności ma daleko idące konsekwencje.
Po pierwsze, jest to doskonała realizacja zasady wczesnego testowania. Defekty są wykrywane natychmiast, na etapie pisania kodu, a nie dopiero w późniejszych fazach.
Po drugie, takie podejście naturalnie wspiera iteracyjny model wytwarzania – system jest budowany małymi krokami, a każdy krok jest natychmiast weryfikowany przez testy.
Po trzecie, testy stają się żywą, wykonywalną specyfikacją systemu. Zamiast polegać wyłącznie na dokumentach tekstowych, mamy zestaw testów, które precyzyjnie opisują, jak system powinien działać.
Co więcej, te podejścia silnie promują współpracę w zespole i lepsze zrozumienie wymagań.
Jak podkreśla sylabus ISTQB, TDD, ATDD i BDD są podobnymi podejściami, w ramach których testy traktuje się jako czynnik określający sposób prowadzenia prac programistycznych.
Wszystkie realizują zasadę wczesnego testowania i wspierają podejście „Shift Left” (przesunięcie w lewo), ponieważ testy są definiowane przed rozpoczęciem pisania kodu produkcyjnego.
Przyjrzyjmy się bliżej każdemu z nich.
Wytwarzanie Sterowane Testami (Test-Driven Development - TDD)
TDD jest techniką programistyczną spopularyzowaną przez Kenta Becka, jednego z twórców eXtreme Programming (XP).
Koncentruje się ona głównie na poziomie kodu, czyli na testach jednostkowych (modułowych).
Cykl pracy w TDD jest bardzo krótki i powtarzalny, często nazywany cyklem „Red-Green-Refactor”:
- Red (Czerwony): Programista pisze mały, zautomatyzowany test jednostkowy dla nowej, niewielkiej funkcjonalności lub poprawki. Ponieważ kod implementujący tę funkcjonalność jeszcze nie istnieje, test oczywiście kończy się niepowodzeniem (jest „czerwony”). Ten krok jest kluczowy, ponieważ upewnia nas, że test faktycznie sprawdza to, co powinien, i że nie przejdzie przypadkowo.
- Green (Zielony): Programista pisze minimalną ilość kodu produkcyjnego potrzebną do tego, aby napisany wcześniej test zakończył się powodzeniem (stał się „zielony”). Na tym etapie nie dba się jeszcze o elegancję czy optymalizację kodu – celem jest jedynie sprawienie, by test przeszedł.
- Refactor (Refaktoryzacja): Gdy test jest „zielony”, programista może bezpiecznie przystąpić do refaktoryzacji, czyli poprawy struktury i czytelności zarówno kodu produkcyjnego, jak i kodu testowego, bez zmiany ich zewnętrznego zachowania. Istniejący zestaw testów (w tym ten właśnie napisany) służy jako siatka bezpieczeństwa, która natychmiast wykryje, jeśli refaktoryzacja przypadkowo wprowadzi błąd.
Ten cykl jest powtarzany dla każdej kolejnej, małej części funkcjonalności.
W rezultacie TDD prowadzi do powstania kodu, który jest w pełni pokryty testami jednostkowymi od samego początku.
Testy te stanowią nie tylko mechanizm weryfikacji poprawności, ale także dokumentację działania poszczególnych modułów.
Co ważne, TDD wymusza myślenie o projekcie i testowalności kodu jeszcze przed jego napisaniem.
Programiści muszą zastanowić się, jak dana funkcjonalność ma działać i jak ją przetestować, co często prowadzi do lepszego, bardziej modularnego projektu.
Zamiast polegać na rozbudowanych, formalnych dokumentach projektowych, to właśnie przypadki testowe kierują procesem tworzenia kodu.
Korzyści z TDD obejmują m.in.: wyższą jakość kodu z mniejszą liczbą defektów, lepszy projekt (bardziej modularny, luźniej powiązany), pewność podczas refaktoryzacji i wprowadzania zmian, oraz żywą dokumentację w postaci testów.
Wyzwania mogą obejmować początkową krzywą uczenia się dla programistów, potrzebę dyscypliny w przestrzeganiu cyklu oraz potencjalnie większy początkowy nakład pracy (choć często zwraca się on w dłuższej perspektywie).
Wytwarzanie Sterowane Testami Akceptacyjnymi (Acceptance Test-Driven Development - ATDD)
ATDD przenosi ideę TDD na wyższy poziom abstrakcji – poziom wymagań biznesowych i kryteriów akceptacji.
Podczas gdy TDD skupia się na testach jednostkowych pisanych przez programistów, ATDD koncentruje się na testach akceptacyjnych, które definiują, kiedy dana historyjka użytkownika (user story) lub funkcjonalność jest uznana za zrealizowaną z perspektywy biznesowej.
Kluczowym elementem ATDD jest współpraca między przedstawicielami biznesu (np. Product Ownerem, analitykiem), programistami i testerami w celu wspólnego zdefiniowania kryteriów akceptacji dla każdej historyjki użytkownika, jeszcze przed rozpoczęciem jej implementacji.
Te kryteria akceptacji są następnie przekształcane w konkretne, zautomatyzowane testy akceptacyjne.
Podobnie jak w TDD, testy te są pisane przed kodem produkcyjnym.
Zespół deweloperski implementuje funkcjonalność, dążąc do tego, aby wszystkie zdefiniowane testy akceptacyjne zakończyły się powodzeniem.
Proces ten często przebiega iteracyjnie w ramach cyklu ATDD:
- Discuss (Dyskutuj): Zespół (biznes, programiści, testerzy) dyskutuje nad historyjką użytkownika, aby upewnić się, że wszyscy mają wspólne zrozumienie wymagań i oczekiwanego zachowania.
- Distill (Destyluj): Na podstawie dyskusji zespół formułuje konkretne kryteria akceptacji, często w formie przykładów lub scenariuszy.
- Develop (Rozwijaj): Zespół implementuje testy akceptacyjne na podstawie kryteriów, a następnie pisze kod produkcyjny, aby te testy przeszły.
- Demo (Demonstruj): Zespół demonstruje działającą funkcjonalność, używając testów akceptacyjnych jako potwierdzenia, że wymagania zostały spełnione.
ATDD kładzie silny nacisk na współpracę i komunikację w zespole.
Pomaga uniknąć nieporozumień dotyczących wymagań, ponieważ są one od razu precyzowane w formie testowalnych kryteriów.
Testy akceptacyjne stają się wspólnym językiem dla całego zespołu i służą jako żywa dokumentacja wymagań.
Podobnie jak TDD, ATDD promuje wczesne testowanie i budowanie jakości od początku.
Wytwarzanie Sterowane Zachowaniem (Behavior-Driven Development - BDD)
BDD jest rozwinięciem i udoskonaleniem koncepcji TDD i ATDD, wprowadzonym przez Dana Northa.
Podobnie jak ATDD, BDD koncentruje się na współpracy między biznesem, programistami i testerami oraz na definiowaniu wymagań w formie testowalnych scenariuszy.
Główną różnicą i cechą charakterystyczną BDD jest użycie specyficznego, ustrukturyzowanego języka naturalnego do opisu oczekiwanego zachowania systemu.
Najczęściej stosowaną składnią jest Gherkin, znana z narzędzia Cucumber, która wykorzystuje słowa kluczowe: Given (Mając), When (Kiedy), Then (Wtedy).
Scenariusz BDD opisuje zachowanie systemu z perspektywy użytkownika lub interesariusza:
- Given (Mając): Opisuje warunki początkowe lub kontekst przed wykonaniem akcji.
- When (Kiedy): Opisuje akcję lub zdarzenie, które wyzwala dane zachowanie.
- Then (Wtedy): Opisuje oczekiwany rezultat lub stan systemu po wykonaniu akcji.
Przykład scenariusza BDD dla funkcji logowania:
Feature: Logowanie użytkownika
Scenario: Pomyślne logowanie zarejestrowanego użytkownika
Given Użytkownik jest na stronie logowania
And Użytkownik "JanKowalski" istnieje z hasłem "tajneHaslo"
When Użytkownik wprowadza "JanKowalski" w pole "Nazwa użytkownika"
And Użytkownik wprowadza "tajneHaslo" w pole "Hasło"
And Użytkownik klika przycisk "Zaloguj"
Then Użytkownik powinien zostać przekierowany na stronę główną
And Użytkownik powinien zobaczyć powitanie "Witaj, JanKowalski!"
Te scenariusze, napisane w języku zrozumiałym dla wszystkich członków zespołu (w tym nietechnicznych), służą jako podstawa do dyskusji, precyzowania wymagań i tworzenia zautomatyzowanych testów.
Narzędzia takie jak Cucumber, SpecFlow czy Behave potrafią parsować te scenariusze i wiązać je z kodem testującym (tzw. step definitions), który wykonuje odpowiednie akcje i weryfikuje oczekiwane rezultaty.
BDD, podobnie jak ATDD, silnie promuje współpracę, wspólne zrozumienie wymagań i tworzenie żywej dokumentacji.
Dodatkowo, ustrukturyzowany język Gherkin pomaga w utrzymaniu spójności i czytelności scenariuszy.
Podsumowanie
Podejścia takie jak TDD, ATDD i BDD reprezentują zmianę paradygmatu w myśleniu o testowaniu – od weryfikacji post-factum do aktywnego kierowania procesem wytwarzania.
TDD koncentruje się na poziomie kodu i testach jednostkowych, napędzając tworzenie kodu przez cykl Red-Green-Refactor.
ATDD i BDD przenoszą tę ideę na poziom wymagań, wykorzystując testy akceptacyjne (BDD dodatkowo używa ustrukturyzowanego języka naturalnego) do definiowania i weryfikowania oczekiwanego zachowania systemu w ścisłej współpracy z biznesem.
Wszystkie te podejścia promują wczesne testowanie, lepszą jakość, współpracę i tworzenie żywej, wykonywalnej dokumentacji.
Są one szczególnie popularne w kontekście metodyk zwinnych, ale ich zasady mogą być adaptowane również w innych modelach SDLC.