18 kwi 20228 min czytania
Dawid Karczewski
Senior full stack developer i CTO w Ideamotive.
Współczesne środowisko wytwarzania oprogramowania jest na tyle zróżnicowane, że mieści w sobie różne podejścia do kodowania. Najstarsze i najbardziej konwencjonalne to metoda sterowana architekturą. Polega na tym, że aplikacja powstaje ze wszystkimi pożądanymi funkcjami, a testy uruchamia się dopiero potem. U jej podstaw leży więc koncepcja „test-last”.
Podejście to wywodzi się z czasów, gdy zwinne wytwarzanie oprogramowania nie było jeszcze powszechnie stosowane. Największą wadą tej metody jest to, że cały zespół musi godzinami, a nawet całymi dniami przeglądać całą bazę kodu, żeby poprawić jedną linijkę, gdy któryś z testów nie przechodzi.
Przyzwoitą alternatywą dla podejścia sterowanego architekturą jest test-driven development (TDD). Metoda pojawiła się w 1999 roku jako koncepcja „test-first”, będąca elementem extreme programming (XP). Później TDD stało się jednak samodzielną metodyką.
Test-driven development proponuje kolejność działań odwrotną do programowania sterowanego architekturą: testy dla każdej jednostki kodu powstają, zanim pojawi się sam kod. Na pierwszy rzut oka może to brzmieć nieracjonalnie i czasochłonnie. Efekt końcowy jest jednak odwrotny: na produkcję trafia wyłącznie czysty kod, bez zbędnego czasu traconego na poprawianie błędów.
Czy test-driven development ma sens w każdym projekcie? Czy da się je zastosować w programowaniu w Pythonie? Gdzie znaleźć programistów Pythona z praktycznym doświadczeniem w TDD? Ten wpis odpowiada na te pytania i przedstawia podstawy test-driven development.
TDD to technika wytwarzania oprogramowania oparta na bardzo krótkich, powtarzalnych cyklach złożonych z trzech etapów:
Jednym z kluczowych aspektów test-driven development jest to, że programiści muszą tworzyć testy sami, bez przydzielania testerów. Zespoły trzymające się z dala od TDD mogą argumentować, że pisanie testów to nie sprawa programisty. Jest to prawdą dla tradycyjnego podejścia test-last, w którym testy uruchamia się post factum, po zakończeniu danego etapu prac. W efekcie pojawiają się typowe wady metody test-last:
Programiści pracujący w TDD myślą inaczej: dla każdego modułu powinien istnieć test, zanim programista napisze do niego kod. Testy modułów muszą więc tworzyć wyłącznie programiści. Co więcej, pierwszy test zawsze kończy się niepowodzeniem, bo kodu jeszcze nie ma. Dlaczego tak? Warto przyjrzeć się typowemu cyklowi TDD dokładniej.
Zwolennicy TDD dzielą cykl wytwarzania na trzy etapy, a każdy z nich na kilka kroków. Pierwszy, „czerwony” etap składa się z następujących kroków:
Krok 1: zastanów się nad modułem kodu, który ma powstać dla konkretnej funkcji;
Krok 2: napisz test modułu;
Krok 3: uruchom test, który nieuchronnie zakończy się niepowodzeniem.
Nie bez powodu część programistów nazywa krok 2 „pisaniem testu, który nie przechodzi”: nie ma jeszcze kodu zdolnego go zaliczyć. „Żaden test nie zasługuje na zaufanie, dopóki choć raz nie zawiedzie” - mówią. To rodzaj automotywacji: nieudany test skłania programistów do zastanowienia się nad poprawnością funkcjonalną przyszłego kodu albo nad samym testem.
Drugi, „zielony” etap obejmuje:
Krok 4: napisz minimalny możliwy kod, który przejdzie test. Jeśli test świeci na zielono, funkcjonalność kodu jest poprawna. Kluczowe jest, żeby kod raz test zaliczył, a raz go nie zaliczył. O pomyłkę łatwo: testy zawsze przechodzące, tak samo jak zawsze niezaliczane, nie wymagają stworzenia niczego szczególnego. Ale test, który może zarówno przejść, jak i nie przejść, na pewno sprawdza jakąś logikę.
Krok 5: Uruchom test ponownie, żeby upewnić się, że funkcjonalność kodu działa poprawnie.
Ostatni etap test-driven development, „refaktoryzacja”, oznacza pisanie czystego kodu bez zbędnych elementów i powtarzanie kroków od 1 do 5. Im krótszy cały cykl, tym lepiej.
Choć test-driven development trudno uznać za uniwersalne podejście stosowane w każdym projekcie, część oczywistych korzyści TDD obejmuje szerokie spektrum praktyk programistycznych. Poniższe potrafią zoptymalizować pracę nad kodem - to tylko kilka z nich:
Gdy firma zatrudnia programistów Pythona nieobeznanych z test-driven development, może pojawić się pewien opór, wynikający z uprzedzeń i mitów krążących wśród programistów. U ich podłoża leży brak wiedzy o podejściu test-driven. Choć potrafią brzmieć bardzo logicznie, kontrargumentów jest dość, by obalić każde błędne wyobrażenie o test-driven development.
Mit 1: TDD to wyłącznie testowanie i automatyzacja testów.
Wyjaśnienie: TDD to metodyka programowania oparta na podejściu „test-first”.
Mit 2: TDD oznacza brak projektowania.
Wyjaśnienie: TDD obejmuje analizę krytyczną i projektowanie zgodne z wymaganiami technicznymi.
Mit 3: TDD działa na poziomie pojedynczego modułu kodu.
Wyjaśnienie: Nic nie stoi na przeszkodzie, by stosować TDD zarówno na poziomie integracji, jak i systemu.
Mit 4: TDD nie sprawdza się w projektach z tradycyjnymi cyklami testowymi.
Wyjaśnienie: TDD jest popularne w extreme programming i innych odmianach zwinnego wytwarzania. Jednocześnie nic nie stoi na przeszkodzie, by stosować TDD na etapie wytwarzania dowolnego tradycyjnego projektu, obok jego etapu testów po zakończeniu prac.
Mit 5: TDD to tylko narzędzie.
Wyjaśnienie: TDD to metodyka, w której każdy nowy test modułu trafia do zestawu testów automatycznych. Wszystkie testy trzeba uruchamiać po każdej zmianie w istniejącym kodzie oraz po każdej refaktoryzacji. Różne narzędzia automatyzacji testów ułatwiają więc TDD, które jest czymś więcej niż tylko narzędziem.
Mit 6: TDD oznacza przeniesienie testów akceptacyjnych z testerów na programistów.
Wyjaśnienie: TDD nie zamienia testerów na programistów w testach akceptacyjnych, ponieważ zestaw specyficznych testów skoncentrowanych na wytwarzaniu - takich jak testy jednostkowe i testy modułów - uruchamiają programiści na etapie wytwarzania.
Test-driven development może zostać przyjęte jako metodyka przez programistów Pythona, gdy ich projekt spełnia określone warunki. Część z nich należy do warunków zewnętrznych, a część do wewnętrznych. Wybór zależy więc od następujących czynników:
Poniższe kryteria pomagają rozpoznać przypadki, w których TDD ma sens:
Jak widać, test-driven development nie jest panaceum. Jeśli TDD nie pasuje do Twojego projektu, prace zwalniają, a programiści dochodzą do błędnych uogólnień, takich jak:
Żeby uniknąć takich ponurych wahań, warto ocenić TDD z perspektywy własnej działalności programistycznej. Test-driven development raczej nie jest zalecane, jeśli:
To, czy stosować TDD, jest kwestią indywidualną. Wiele zależy od projektu, liderów zespołu programistycznego i wartości panujących w firmie. TDD nie łamie wzorców, jeśli pamięta się o kilku podstawowych zasadach:
To, czy Python jest odpowiednią technologią do test-driven development, wydaje się pytaniem bezprzedmiotowym, jak uważa wielu inżynierów programowania w Pythonie. To właśnie dostępność odpowiednich zestawów testów automatycznych i frameworków decyduje o tym, jak dobrze dana technologia sprawdza się w TDD. Python jest w tym kontekście jednym z niewielu języków programowania na tyle bogatych w narzędzia do nowoczesnych praktyk testowych.
Python słynie z prostej czytelności i łatwości pisania kodu. Inżynierowie automatyzacji w Pythonie nie muszą używać kompilatorów do konwersji kodu, ponieważ jest to język skryptowy. Przewodnik po automatyzacji „Zen of Python” mówi, że testy napisane w zestawie testowym są łatwe do czytania i wyjaśnienia.
Selenium to framework automatyzacji, który pozwala na przykład tworzyć testy automatyczne w przeglądarkach z elegancką prostotą. Skrypty testów automatycznych powstają dzięki współpracy Selenium WebDrive z takimi przeglądarkami jak Mozilla Firefox, Google Chrome, Internet Explorer, Safari i Opera. Narzędzie jest kompatybilne z Pythonem i innymi językami skryptowymi, co pozwala tworzyć szybkie, powtarzalne testy w pipeline’ach continuous integration.
Kolejnym frameworkiem testów automatycznych skoncentrowanym na Pythonie jest Robot. Framework pozwala programistom pisać kod dopiero wtedy, gdy istnieje niezaliczony test. Trudno o bardziej wyrazistą cechę test-driven development. Robot jest napisany w Python i skierowany do organizacji, które praktykują Agile i TDD.
Wielu programistów Pythona uważa PyTest za najlepszy framework testów automatycznych w historii. Testy jednostkowe, end-to-end i integracyjne łatwo w nim zaimplementować. Niewielu programistów Pythona woli domyślny zestaw testowy PyUnit (unittest) od PyTest, bo ten drugi daje znacznie szerszy zakres opcji testowania.
Poza frameworkami testowymi dostępne są też dedykowane biblioteki Pythona nadające się do TDD. Hypothesis to na przykład ta, która pomaga tworzyć mocniejsze i prostsze w pisaniu testy jednostkowe, potrafiące znaleźć słaby kod tam, gdzie trudno się go spodziewać. Biblioteka bezproblemowo współpracuje z każdym zestawem testowym.
Jak widać, Python jest bogaty w zestawy narzędzi testowych, które czynią test-driven development bardzo odpowiednim podejściem do niemal każdego oprogramowania napisanego w Pythonie.
Odpowiedź na pytanie „dlaczego warto stosować test-driven development” ma kilka możliwych wariantów. Przede wszystkim TDD to bezkompromisowa jakość kodu dopracowanego dzięki licznym refaktoryzacjom. Debugowanie odbywa się organicznie przez cały cykl życia wytwarzania.
Kolejny aspekt to czas (a więc i pieniądze) zaoszczędzony dzięki krótszym testom akceptacyjnym przed wdrożeniem. Znacznie bardziej elegancki kod powstaje w krótszym czasie, gdy progresywne podejścia zwinne, takie jak test-driven development, idą w parze z continuous integration/continuous delivery.
Niewiele technologii jest bardziej zgodnych z TDD niż Python: dla tego języka dostępnych jest wiele narzędzi do testów automatycznych. Test-driven development w Pythonie to przepis na sukces dla klientów, którzy nadążają za duchem czasu.
Skontaktuj się z nami już dziś, jeśli podzielasz naszą wizję idealnego połączenia „TDD + Python”, które sprosta wymaganiom każdego projektu programistycznego. Najwyższej klasy usługi programistyczne i dedykowane zespoły profesjonalnych programistów Pythona są zawsze dostępne w rozsądnej cenie.
Dawid jest full stack developerem. Tworzy aplikacje w Ruby on Rails i React Native od pierwszego pomysłu aż po wdrożenie. Buduje dla naszych klientów rozwiązania, które pomagają im rosnąć.
Zobacz wszystkie wpisy autoraPopularne artykuły
21 inspirujących projektów UI aplikacji mobilnych na 2023 rok
Michał Pruciak 7 min czytania
MedTech vs HealthTech vs BioTech: jakie są różnice?
Michał Pruciak 7 min czytania
10 biznesowych zastosowań sieci neuronowych (z przykładami!)
Michał Pruciak 4 min czytania
10 przykładów dobrych praktyk w web designie na 2023 rok
Adam Kozłowski 7 min czytania
28 znanych aplikacji webowych napisanych w PHP
Dawid Karczewski 14 min czytania
Jakich usług programistycznych szukasz?
W naszej sieci talentów czekają dziesiątki zweryfikowanych specjalistów Python.
Dane rejestrowe:
Firma
Usługi
Najczęściej poszukiwani specjaliści
Ocena 4,8 / 5,0 od klientów z różnych branż i lokalizacji.