Blog
Istnieją dwa popularne style formatowania opisów testów: it('should do something')
i it('does something')
. Którego stylu powinniśmy używać? Czy któryś z nich jest obiektywnie lepszy, czy jest to wyłącznie kwestia gustu?
By łatwiej nam było podjąć decyzję, przyjrzyjmy się obu stylom, should
i does
, z trzech różnych punktów widzenia:
Formatowanie wyników testu
Porównajmy jak testy tej samej funkcjonalności, zapisane w stylu should
oraz does
, mogłyby wyglądać wyświetlone w konsoli:
Styl should
:
Guest User
should have temporary account
should not have permanent account
should be able to read posts
should not be able to create posts
Styl does
:
Guest User
has temporary account
does not have permanent account
can read posts
cannot create posts
Najbardziej widoczną różnicą jest to, że słowo should
funkcjonuje jak znacznik listy wypunktowanej, stały separator formujący wymagania w schludny ciąg. Jest to wyłącznie kwestia upodobań. Niektórzy twierdzą, że poprawia to czytelność, sprawiając, że łatwiej “przeskanować” testy wzrokiem. Dla innych (ja wliczam się do tej grupy) jest to po prostu niepotrzebny szum, który nie dokłada żadnej użytecznej informacji – i sprawia, że testy są mniej czytelne.
Drugą, mniej rzucającą się w oczy różnicą, jest to w jaki sposób oba style wpływają na zanegowane wymagania. W stylu should
negacja jest ustandaryzowana – test zawsze zaczyna się albo od prefixu should
albo should not
, przez co od razu widać, czy opisuje on przypadek pozytywny czy negatywny. W stylu does
pozytywne i negatywne przypadki mają za każdym razem inne nazwy (np. has
i does not have
, can
i cannot
, writes
i does not write
itp.). Według niektórych osób, testy z ustandaryzowanym stylem negacji są łatwiejsze do zrozumiena. Moja osobista opinia jest taka, że aby w pełni zrozumieć wszystkie implikacje testu i tak trzeba zrozumieć co konkretnie jest negowane, więc ustandaryzowany prefix negacji nie rozwiązuje problemu, sprawia jedynie, że opis staje się dłuższy.
Podsumowując: z punktu widzenia czytelności wyników testu, preferuję wersję does
, choć jest to kwestia indywidualnego gustu i nie ma obiektywnych argumentów za ani przeciw któremukolwiek ze styli.
Dokumentacja kontra specyfikacja
Istnieje subtelna, ineresująca różnica pomiędzy stylami should
i does
. Pierwszy z nich skłania się bardziej ku specyfikacji, podczas gdy drugi ku dokumentacji.
Fraza rozpoczynająca się słowem should
(powinien) w naturalny sposób pasuje do nowych wymagań. Brzmi ona dobrze gdy specyfikujemy funkcjonalność, która jeszcze nie istnieje w sytemie: The system should allow an user to view his payment history
, The sign up should require a valid email
itp.
Z drugiej strony, should
niezbyt pasuje do dokumentacji. W instrukcji użytkownika dużo lepiej brzmi sformułowanie An eraser tool cleans the canvas
niż An eraser tool should clean the canvas
. Użytkownik spodziewa się, że powiesz mu, jak twój system działa, co on faktycznie robi a nie co powinien robić. (An eraser should clean the canvas
– “gumka” powinna wyczyścić obszar rysunku; Powinna? Czyli może nie wyczyścić? W jakich okolicznościach?).
To prowadzi nas do interesującego pytania: Jak traktujemy nasze testy? Jako specyfikację, czy jako dokumentację?
Jeżeli stosujesz TDD, piszesz testy najpierw, dla funkcjonalności, która jeszcze nie istnieje. Wydaje się więc naturalne, by traktować je jako specyfikację (frameworki w stylu BDD wręcz jawnie zastępują słowo “test” słowem “spec”). Z drugiej strony, nie kasujesz testów po tym jak napiszesz kod – pozostawiasz je by funkcjonowały jako dokumentacja, by pomóc przyszłemu Tobie i członkom Twojego zespołu przypomnieć sobie, jak system działa.
Która z tych dwóch faz jest ważniejsza? Z jednej strony faza specyfikacji jest kluczowa, ponieważ to właśnie ona kieruje designem systemu. Z drugiej strony, faza dokumentacji jest dużo dłuższa. Piszesz kod tylko raz, a żyć z nim musisz potem nieraz przez lata (wielokrotnie ponownie go czytając, refaktoryzując, wyjaśniając nowym członkom zespołu itd.).
Osobiście, skłaniam się ku stylowi dokumentacji (does
). Jak dla mnie, bardziej naturalnie się go czyta podczas fazy utrzymania kodu (która, jak powyżej wspomniałem, trwa znacznie dłużej niż faza tworzenia kodu). Ponadto, z mojego doświadczenia, używanie stylu dokumentacji nie ogranicza mojej zdolności do projektowania kodu poprzez “słuchanie testów” w trakcie fazy specyfikacji.
Celowa niejednoznaczność kontra klarowna intencja
Ostania subtelna różnica pomiędzy stylami should
i does
leży w odczuwalnym poziomie niejednoznaczności.
Styl does
jest bezkompromisowy, z klarowną, zdecydowaną intencją. System robi to i to. Jeżeli nie robi (jeżeli test się “wysypuje”), znaczy to, że system jest zepsuty, że w kodzie istnieje błąd.
Styl should
pozostawia więcej miejsca na dyskusję. Jeżeli stwierdzasz “system robi to i to” nie pozostawiasz miejsca na polemikę. Jeżeli stwierdzasz “System powinien robić to i to”, otwierasz się na pytania w stylu “Czy rzeczywiście powinien? Jesteśmy tego pewni?”. (Takie otwarte podejście jest zalecane przez twórcę BDD, Dana Northa, w jego poście wprowadzającym do tej metody).
Styl should
wpływa także na to, jak traktujemy testy, które nie “przechodzą”. Jeżeli system jedynie powinien coś robić, zakończony niepowodzeniem test nie musi koniecznie znaczyć, że w kodzie znajduje się błąd. Może on równie dobrze świadczyć o tym, że nasze poprzednie założenie na temat tego, co system powinien robić, jest niepoprawne i że powinniśmy przedyskutować jeszcze raz wymagania. Niektórzy nawet posuwają się aż do stwierdzenia, że nawet w przypadku faktycznego błędu w kodzie, styl does
kłamie, ponieważ mówi on, że system coś robi, podczas gdy tak na prawdę w tej chwili tego nie robi – w związku z czym styl should
jest bardziej poprawny.
Jeżeli chodzi o określenie intencji, wolę styl should
niż does
. Styl should
jest bardziej uczciwy i lepiej sprawdza się jako inicjator dyskusji, co jest na prawdę ważne, jeśli chcemy być zwinni w stosunku do naszych wymagań.
Którego stylu powinienem w takim razie używać?
Jak widać, jest to głównie kwestia niuansów, a w dużej części wyłącznie indywidualnego gustu. Osobiście, skłaniam się nieco ku stylowi it does
. Wprowadza on mniej szumu i lepiej się go czyta, a przy odpowiednim mentalnym nastawieniu nadal mogę być równie otwarty na dyskusję jak w przypadku stylu should
. Jednakże nie podchodzę do tego dogmatycznie. Mogę pracować w dowolnym ze styli, jeśli tylko jest on konsekwentnie stosowany w całym projekcie.
Nie będę próbował Cię przekonywać ani do stylu should
ani does
. Wybierz ten, z którym się lepiej czujesz i który pozwala Ci wygodniej rozumować na temat zachowania systemu. Mam jedynie nadzieję, że powyższa analiza pomoże Ci zdecydować w bardziej świadomy sposób.
Chętnie dowiedziałbym się, co sprawdza się w Twoim przypadku. Który styl opisywania testów wolisz? Podziel się swoim zdaniem w komentarzach poniżej!