Wypróbuj

Nozbe - get things done

i zwiększ swoją produktywność

2# Jasmine – testowanie zachowań

2

Hej, sorry za tę przerwę! Dopadło mnie chyba to samo o czym pisał ostatnio procent… No ale nic to, oto jestem z powrotem z nowymi siłami do blogowania! 🙂 A dzisiejszym wpisem postanowiłem kontynuować temat testowania kodu napisanego w JavaScript. Ostatnio zrobiłem krótki wstęp do frameworka Jasmine – jeśli jesteś nowicjuszem w temacie testów jednostkowych w JavaScript lub nie wiesz zupełnie nic na temat frameworka Jasmine, to zachęcam do przeczytania tego wpisu w pierwszej kolejności 🙂 Dziś natomiast dowiemy się trochę więcej na temat tego jak wygląda w praktyce testowanie z Jasmine (a dokładniej, napiszę trochę o specjalnej składni, ułatwiającej testowanie zachowań).

Behavior-driven czyli testowanie zachowań

Jak wspominałem już w poprzednim wpisie, Jasmine jest tak skonstruowany aby testy pisane za jego pomocą jak najlepiej odzwierciedlały to co dany test ma testować. Takie podejście nazywa się zwykle „behavior-driven testing” czyli po naszemu po prostu testowanie zachowań. Aby to umożliwić, w Jasmine wprowadzono specjalną składnię – popatrzmy więc jeszcze raz na przykład z poprzedniego wpisu:

describe('A suite', function() {
  it('contains spec with an expectation', function() {
    expect(true).toBe(true);
  });
});

Każdy test w Jasmine rozpoczyna się od globalnej funkcji describe, która przyjmuje dwa parametry: pierwszy z nich to nazwa lub lepiej opis tego co jest w danym przypadku testowane – powinien odpowiadać na pytanie „kto? co?”; drugi parametr to funkcja wywołania zwrotnego, której implementacja stanowi konkretny test. Całe domknięcie funkcji describe stanowi natomiast zestaw testów (ang. test suite) danej funkcjonalności (opisanej/nazwanej przez pierwszy, tekstowy parametr). Jak widać powyżej, we wnętrzu tej funkcji anonimowej znajduje się wywołanie innej globalnej funkcji Jasmine, a mianowicie it. Funkcja ta stanowi specyfikację konkretnego testu – w świecie Jasmine takie specyfikacje nazywane są „spec’ami”. Widzimy powyżej, że funkcja it, również przyjmuje jako pierwszy parametr wartość tekstową – tutaj powinno się wpisywać opis oczekiwanego zachowania testowanej części kodu. Łącząc razem tekst podany w pierwszym parametrze funkcji describe i w pierwszym parametrze funkcji it, powinniśmy otrzymać poprawną sentencję – w powyższym przykładzie mamy:

„A suite contains spec with expectation”

Czyli po naszemu „zestaw zawiera specyfikację wraz z oczekiwaniem” co dokładnie opisuje co jest przedmiotem testu i jakie jest oczekiwane zachowanie tego czegoś.

Idźmy dalej z naszym przykładem… Funkcja it, podobnie jak poprzednio describe, przyjmuje jako drugi parametr wywołanie zwrotne. Jego implementacja zawiera odpowiednie asercje nazywane w Jasmine oczekiwaniami (ang. expectations). Jak widać w powyższym przykładzie, oczekiwanie takie buduje się rozpoczynając od wywołania funkcji expect i podając jej jako parametr wartość testowaną. Następnie, stosując interfejs typu „fluent” wywołujemy kolejną funkcję (w tym przypadku jest to toBe), która z kolei przyjmuje jako parametr wartość oczekiwaną (funkcja taka jak toBe jest tzw. „matcherem” – napiszę o tym szerzej w kolejnym wpisie).

Zachowania warunkowe

Opisany powyżej przykład jest oczywiście maksymalnie uproszczony. Jednak w logice biznesowej jak w życiu 😛 wiele rzeczy dzieje się tylko w przypadku jakichś określonych warunków. W Jasmine testujemy takie zachowania poprzez zagnieżdżanie (zgrupowanie) zestawów testów. Spójrzmy na przykład:

describe('A car', function() {
    var car = new Car();

    it('have four wheels', function() {
        expect(car.wheelCount).toEqual(4);
    });

    describe('when you press a gas pedal', function(){
        car.pressGas();

        it('is moving', function(){
            expect(car.isMoving).toBe(true);
        });
    });
});

Tutaj widzimy już trochę bardziej „skomplikowany” zestaw testów. Jak można zauwazyć, testujemy zachowania obiektu car – najpierw prosty test na ilość kół (nie ma tutaj jeszcze niczego czego bym nie opisał w poprzednim akapicie). Ciekawie robi się dopiero w linii 8 (odpowiednio oznaczona) – we wnętrzu jednej funkcji describe mamy kolejne jej wywołanie! Ciekawy jest też pierwszy, tekstowy parametr wywołania:

„when you press a gas pedal”

Czyli przedmiotem tego podrzędnego zestawu testów jest sytuacja (warunkowa) kiedy to naciśnięty zostanie pedał gazu (tak zagnieżdżony zestaw testowy nadal odnosi się do przedmiotu testów nadrzędnego zestawu – w naszym przypadku jest to „A car”). Dalej mamy już sam „spec” zawierający oczekiwanie, że samochód się porusza (czyli cała sentencja dla tego testu brzmi „A car, when you press a gas pedal, is moving”).

Generalnie, można też powiedzieć, że funkcja describe służy do grupowania powiązanych tematycznie testów („spec’ów”) – w naszym przykładzie najpierw zgrupowaliśmy wszystkie „spec’i” dotyczące obiektu car, a następnie stworzyliśmy podgrupę zawierającą wszystkie „spec’i” dotyczące naciśnięcia pedału gazu.

Podsumowanie

Tym sposobem dobrnęliśmy do końca dzisiejszego wpisu – myślę, że powrót po przerwie nie może być zbyt intensywny 😉 Mam nadzieję, że teraz testowanie zachowań za pomocą frameworka Jasmine nie jest już dla Was żadną zagadką… Od razu spieszę poinformować, że to nie koniec wpisów o testowaniu w Jasmine – na pewno pojawi się na ten temat jeszcze jeden post ponieważ,  tak jak już wcześniej wspomniałem, opisu wymagają jeszcze tzw. „matcher’y”. Od razu więc zapraszam! 🙂

CHCESZ DARMOWEGO E-BOOKA?

Jeśli chcesz otrzymać mojego e-booka: Rozmowa Kwalifikacyjna - pytania z podstaw JavaScript zostaw mi swój e-mail:

Oprócz tego co poniedziałek dostaniesz maila z listą moich wpisów z poprzedniego tygodnia!

  • Piotr

    Zgrabny wpis 🙂
    Mam nadzieję Bartku że poruszysz wątek testów asynchronicznych oraz wykorzystania mocków/stubów. W zasadzie to mógłby powstać zgrabny teścik, gdzie mockujesz wywołanie jQuery.ajax() i czekasz na rezultaty.

    • Bartłomiej Dybowski

      Dzięki! Myślę, że to dobry pomysł – zresztą na pewno tematu testów nie odpuszczę zbyt szybko 😉