fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
5 minut

Niezawodny sposób na naukę testów jednostkowych


22.09.2016

Przez ostatnie dwa lata pojeździłem sporo po firmach ze swoim (zajebistym zresztą ;) ) szkoleniem o testach jednostkowych. Dzięki temu sam uświadomiłem sobie, w jaki sposób posiadłem “wiedzę tajemną” na temat testowania.

Wszystko stało się prostsze, gdy odkryłem, że:

Pisanie testów do istniejącego kodu jest jak gra wstępna po seksie

Testy mają bardzo wiele zalet i służą więcej niż jednemu celowi. Wykorzystanie w pełni ich potencjału jest możliwe tylko wówczas, gdy napiszemy je PRZED testowanym kodem. O różnych rolach testów rozpiszę się innym razem.

TDD or not TDD?

Tak popularne – i często źle rozumiane – Test-Driven Development można podzielić na dwa podejścia.

Podejście pierwsze to takie “prawdziwe” TDD, jak promuje je Uncle Bob Martin czy Kent Beck. Polega na tym, że piszemy testy przez chwilę. Tylko krótką chwilę: do momentu, gdy kod przestaje nam się kompilować. Albo gdy test “nie przechodzi”. Wtedy przeskakujemy do kodu “produkcyjnego” i klepiemy… przez kolejną chwilę. Do momentu, gdy kod zaczyna się kompilować i wszystkie testy przechodzą. Takie przeskakiwanie między kontekstami wymaga bardzo dużo dyscypliny i – szczególnie początkującym – na pewno sprawi sporo trudności. Pełny cykl “test -> kod” zajmuje często mniej niż minutę.

Podejście drugie, które rekomenduję, to “Test-First Approach“. Sprowadza się do prostej zasady: piszemy testy do kodu, którego jeszcze nie mamy. Tylko tyle i aż tyle. Często tworzę wiele testów zanim zabiorę się za kod, który sprawi, że będą one przechodzić. Ba, czasami nawet skupiam się na pisaniu PUSTYCH testów. Ich nazwy pozwolą mi zweryfikować, czy na daną chwilę spisałem w “kompilowalnej” postaci wszystkie wychwycone wymagania, scenariusze, wartości brzegowe. Upewniam się, że niczego nie pominąłem. Dopiero mając taką baterię czerwonych testów zabieram się do faktycznej implementacji wymagań.

Po co takie zabiegi? To proste:

 Kod trudny do przetestowania jest kodem trudnym do utrzymania.

A pisząc testy przed napisaniem właściwego kodu – tworzymy wyłącznie kod testowalny.

Więcej mówiłem na ten temat niedawno w podkaście DevReview (“DevReview #8 O testach z Maciejem Aniserowiczem“). Zachęcam do posłuchania, bo fajna rozmowa nam wyszła.

I pojawia się odwieczne pytanie:

Jak ZMUSIĆ się do pisania testów przed napisaniem kodu?

Wiem, jak ciężko jest zmienić swój sposób kodowania i przestawić się na podejście test-first. W końcu przyzwyczajenie, pielęgnowane od lat, nie umrze tak łatwo. Napiszę linijkę czy dwie, wcisnę F5, kliknę w aplikacji w odpowiedni guzik i tym samym WIEM, ŻE DZIAŁA. Po co mi tutaj testy? Ponownie: do tematu “po co mi testy” wrócimy kiedy indziej.

Zachęcam do przeprowadzenia prostego eksperymentu. U mnie zaproponowana zmiana wpłynęła na wszystko – całe moje podejście do programowania. Na szczęście sposób ten odkryłem stosunkowo wcześnie na swojej ścieżce. Aż dziw, że jeszcze (chyba) o tym nie pisałem.

Eksperyment polega na jednym prostym kroku:

 Pisz kod, którego nie da się uruchomić

W świecie .NET oznacza to: twórz tylko DLLki. Nie pisz kodu w projektach “aplikacyjnych”. Dla programisty chcącego nauczyć się testowania: pojęcia takie jak Main(), exe czy webapp nie istnieją. Zwykłe biblioteki są miejscem, w którym rośnie kodzik z logiką.

Faktyczna APLIKACJA to tylko sposób na zaprezentowanie kodu użytkownikom.

W momencie, w którym uwolnisz się od exeków, odkryjesz śmieszną prawdę: nie jesteś Linusem Torvaldsem. Nie jesteś w stanie zaufać sobie na tyle, aby taki kod pchnąć do repozytorium, dostarczyć do finalnego rozwiązania. Nie możesz go uruchomić, więc jak sprawdzić, że działa? Ano właśnie: pozostają Ci TYLKO TESTY.

Skoro Twój kod może być wykonany tylko i wyłącznie w kontekście testów jednostkowych, to zaczniesz przykładać do nich wagę. Kolejne linijki będą MUSIAŁY być napisane tak, aby testy w łatwy sposób się do nich dobrały. Wtedy przekonasz się też na własnej skórze, że życie jest o wiele prostsze, jeśli testy piszesz najpierw.

I to będzie pierwszy krok. Klęknij, devie. Bach, bach, mieczem bo barach. Powstań, sir-test-devie.

Wkraczasz w piękniejszy świat.

EDIT 06.10.2016: dodałem tekst na temat poruszony w komentarzach: “3 sprawdzone sposoby na wprowadzanie testów do istniejącego kodu“.

Nie przegap kolejnych postów!

Dołącz do ponad 9000 programistów w devstyle newsletter!

Tym samym wyrażasz zgodę na otrzymanie informacji marketingowych z devstyle.pl (doh...). Powered by ConvertKit
Notify of
Kamil Ławniczak
Kamil Ławniczak

Niby ta mini petla TDD ma zapewnic zawsze dzialajaca logike.,
ale mysle ze w druga strone przesadzic tez nie jest dobrze, test mylacy gorszy niz brak.
Test-Pass chyba najwygodniejsze w moim przypadku.

AHA i pisanie testow tam gdzie ich nigdy nie bylo… sadomaso ;0

Koper
Koper

A co w przypadku istniejacego już kodu i potrzeby jego refaktoryzacji? Czy pisanie testów do takiego kodu to gra wstępna po seksie czy też niezbędna antykoncepcja?

Dzik
Dzik

Linus serio nie pisze testów?! A to dzik.

Jacek
Jacek

Siemka
Myślałeś o tym, żeby przygotować szkolenia online dla freelancerów na solidnym poziomie?

Paweł
Paweł

Było by to piękne gdyby nie JS.
Znacie jakieś ciekawe narzędzia do pisania testów jednostkowych dla JS i do testów FrontEndu webowego?
Ja znam Selenium które klika za mnie.

Andrzej
Andrzej

Poza Jasmine jeszcze dosyć popularny zestaw to mocha+chai+sinon. Mocha to dość minimalistyczny framework do testów, chai to bardzo wygodna w użyciu biblioteka asercji a sinon to biblioteka do mocków.
No i jak mowa o frontendzie, to na dłuższą metę nie obejdzie się bez Karmy – narzędzie, które uruchamia przeglądarki i wewnątrz nich uruchamia testy. Szczególnie przydatne do np. uruchomienia testów na raz na kilku przeglądarkach czy wpięcia testów w CI (Jenkins, Travis i reszta)

Beka
Beka

Imho jednak “prawdziwe” TDD jest lepsze, a to ze względu na to, że:
* Wystarczy analityczny tok myślowy, jaki zwykle mamy, kiedy wymyślamy rozwiązanie, od razu przelewać na testy
* Kod produkcyjny wtedy robi dokładnie to i tylko to, co jest wymagane
* Testy są jednocześnie dokumentacją działania kodu, nie zaś dokumentacją wymagań
* Nie marnujemy czasu na zastanawianie się nad edge case’ami, które nigdy nie wystąpią

Dawid K

W TDD można pisać gdy znamy technologię i mamy dobrze opisany cel biznesowy, gdy znamy wejście i wyjście programu. Bo jak nie wiemy, co chcemy osiągnąć, to nie napiszemy sensownych testów. Gdy robimy coś na czuja, w technologii, której się dopiero uczymy, albo coś dopiero badamy (bo np. nie wiemy, czy w ogóle potrzebne nam informacje możemy wyciągnąć) – tam podejście TDD znacznie spowolniłoby (czy wręcz uniemożliwiło) napisanie działającego kodu. Kolejną pułapką związaną z TDD jest fakt, że stosowanie go wszędzie jest stratą czasu. Są ludzie, którzy próbują w ten sposób testować jednostkowo bazę danych albo system plików, w efekcie… Read more »

Jacek
Jacek

“Co do pisania “bez interfejsu” – od zawsze mówię, że testy to powinno być pierwszy UI, który napiszemy do naszej aplikacji. ”

To mi się podoba, ale to wymaga działania, o czym pisze Maciej, totalnego oddzielenia całej logiki od UI. Czasem, np. przy szybkim prototypowaniu, jest to trudne mentalnie :)

Dawid K

Moim zdaniem, to “oddzielenie” to jest właśnie coś, co odróżnia programistów od klepaczy.

aqaque
aqaque

Czyli dlatego tyle nowych freamworków w javascriptcie powstaje. ;)

trackback

[…] Niezawodny sposób na naukę testów jednostkowych […]

trackback

[…] Niezawodny sposób na naukę testów jednostkowych […]

Moja książka

Facebook

Zobacz również