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 :P 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! :)

P.S. Wpis ten jest częścią mini-serii na temat testowania Jasmine. Poniżej wszystkie części tej serii: