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ń).

2# Jasmine - testowanie zachowań
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: