Wprowadzenie do testów jednostkowych jaśmin

jaśmin jest najpopularniejszą biblioteką JS do testów jednostkowych aplikacji internetowych. W tym samouczku, przeznaczonym dla początkujących, przedstawimy Ci szybki i kompletny przewodnik po testowaniu z Jasmine.

zapoznasz się z Jasmine, popularnym frameworkiem testowania opartego na zachowaniu dla JavaScript. Zobaczymy również prosty, praktyczny przykład jak pisać testy jednostkowe z Jasmine, które mogą pomóc w łatwym sprawdzaniu błędów w kodzie.

W skrócie, zobaczymy, jak napisać Pakiety testów, specyfikacje i oczekiwania oraz jak zastosować wbudowane matchery jaśmin lub zbudować własne matchery

zobaczymy również, jak można grupować pakiety w celu zorganizowania testów dla bardziej złożonych baz kodu.

przedstawiamy jaśmin

jaśmin jest bardzo popularnym skryptem JavaScript opartym na zachowaniu (w BDD piszesz testy przed napisaniem kodu) do testowania jednostkowego aplikacji JavaScript. Zapewnia narzędzia, które mogą być używane do uruchamiania automatycznych testów zarówno dla kodu synchronicznego, jak i asynchronicznego.

jaśmin ma wiele funkcji, takich jak:

  • jest szybki i ma niskie koszty ogólne i brak zewnętrznych zależności.
  • jest to biblioteka dołączona do baterii i oferuje wszystko, czego potrzebujesz do testowania kodu.
  • jest dostępny zarówno dla Node jak i przeglądarki.
  • może być używany z innymi językami, takimi jak Python i Ruby.
  • nie wymaga DOM.
  • zapewnia czystą i łatwą do zrozumienia składnię, a także bogate i proste API.
  • możemy użyć języka naturalnego do opisania testów i oczekiwanych wyników.

Jasmine jest narzędziem open source dostępnym na licencji MIT. W chwili pisania tego tekstu najnowszą główną wersją jest jaśmin 3.0, który zawiera nowe funkcje i pewne przełomowe zmiany. Wydanie jaśmin w wersji 2.99 będzie zawierało różne ostrzeżenia o deprecjacji dla pakietów, które mają inne zachowanie w wersji 3.0, co ułatwi programistom migrację do nowej wersji.

możesz przeczytać o nowych funkcjach i łamaniu zmian w tym dokumencie.

używając jaśminu

Możesz używać jaśminu na wiele różnych sposobów:

  • w stary sposób, włączając zarówno rdzeń jaśminu, jak i pliki testowe, używając znacznika<script>,
  • jako narzędzia CLI używającego węzła.js,
  • jako Biblioteka w węźle.js,
  • jako część systemu budowania jak Gulp.js lub Grunt.js poprzez grunt-contrib-jasmine i gulp-jasmine-browser

Możesz również użyć Jasmine do testowania kodu Pythona za pomocą jasmine-py, który można zainstalować z PyPI za pomocą poleceniapip install jasmine. Pakiet zawiera zarówno serwer WWW, który obsługuje i wykonuje Pakiet jaśmin dla Twojego projektu, jak i skrypt CLI do uruchamiania testów i ciągłej integracji.

jaśmin jest również dostępny dla projektów Ruby poprzez jaśmin-gem, który można zainstalować dodając gem 'jasmine'do swojego pliku Gemfile i uruchamiając bundle install. Zawiera serwer do obsługi i uruchamiania testów, skrypt CLI, a także generatory dla projektów Ruby on Rails.

teraz skupmy się na tym, jak używać jaśminu z JavaScript:

Korzystanie z samodzielnego jaśminu

Rozpocznij od pobrania najnowszej wersji jaśminu ze strony releases.

następnie po prostu rozpakuj plik zip, najlepiej wewnątrz folderu w projekcie, który chcesz przetestować.

folder będzie zawierał kilka domyślnych plików i folderów:

/src: zawiera pliki źródłowe, które chcesz przetestować. Może to zostać usunięte, jeśli masz już konfigurację folderu projektu lub może być również użyty, gdy jest to właściwe, do hostowania kodu źródłowego.

/lib: zawiera podstawowe pliki jaśmin.

/spec: zawiera testy, które zamierzasz napisać.

SpecRunner.html: ten plik jest używany jako tester. Uruchom swoje specyfikacje po prostu uruchamiając ten plik.

To jest zawartość domyślnego plikuSpecRunner.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>Jasmine Spec Runner v3.2.1</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-3.2.1/jasmine_favicon.png"> <link rel="stylesheet" href="lib/jasmine-3.2.1/jasmine.css"> <script src="lib/jasmine-3.2.1/jasmine.js"></script> <script src="lib/jasmine-3.2.1/jasmine-html.js"></script> <script src="lib/jasmine-3.2.1/boot.js"></script> <!-- include source files here... --> <script src="src/Player.js"></script> <script src="src/Song.js"></script> <!-- include spec files here... --> <script src="spec/SpecHelper.js"></script> <script src="spec/PlayerSpec.js"></script></head><body></body></html>

pamiętaj, że musisz zmienić pliki zawarte w folderach/src I/spec aby zawierać rzeczywiste pliki źródłowe i testowe.

używanie jaśminu jako biblioteki

Możesz również użyć jaśminu jako biblioteki w swoim projekcie. Na przykład następujący kod importuje i wykonuje jaśmin:

var Jasmine = require('jasmine');var jasmine = new Jasmine();jasmine.loadConfigFile('spec/support/jasmine.json');jasmine.execute();

najpierw wymagamy/import jaśminu i używamy metody loadConfigFile()do załadowania pliku konfiguracyjnego dostępnego ze ścieżki spec/support/jasmine.json następnie uruchamiamy jaśmin.

używając jaśminu poprzez CLI

Możesz również użyć jaśminu z CLI, co pozwala na łatwe uruchamianie testów jaśminu i domyślnie wypisywanie wyników w terminalu.

będziemy postępować zgodnie z tym podejściem, aby uruchomić nasze przykładowe testy w tym przewodniku, więc najpierw uruchom następujące polecenie, aby zainstalować jaśmin globalnie:

npm install -g jasmine

aby zainstalować pakiety npm globalnie, konieczne może być uruchomienie sudo w zależności od konfiguracji npm.

teraz utwórz folder dla swojego projektu i przejdź do jego wnętrza:

$ mkdir jasmine-project $ cd jasmine-project

następnie uruchom następujące polecenie, aby zainicjować swój projekt dla jaśminu:

To polecenie po prostu tworzy folder spec I plik konfiguracyjny JSON. Jest to wyjście polecenia dir:

.└── spec └── support └── jasmine.json2 directories, 1 file

jest to zawartość domyślnego pliku jasmine.json:

{ "spec_dir": "spec", "spec_files": pec.js" ], "helpers": , "stopSpecOnExpectationFailure": false, "random": true}
  • spec_dir: określa, gdzie jaśmin szuka plików testowych.
  • spec_files: określa wzorce plików testowych, domyślnie wszystkie pliki JS kończące się ciągami Spec lub spec.
  • helpers: określa, gdzie jaśmin szuka plików pomocniczych. Pliki pomocnicze są wykonywane przed specyfikacją i mogą być używane do definiowania niestandardowych dopasowań.
  • stopSpecOnExpectationFailure: po ustawieniu na true natychmiast zatrzyma specyfikację przy pierwszym niepowodzeniu oczekiwania (może być użyta jako opcja CLI poprzez--stop-on-failure).
  • random: po ustawieniu na true Jasmine pseudo-losowo uruchomi przypadki testowe (może być użyty jako opcja CLI poprzez--random).

tablicespec_files Ihelpers mogą również zawierać wzorce Glob (dzięki pakietowi node-glob) do określania ścieżek plików, które są wzorcami, których zwykle używasz do określenia zestawu plików podczas pracy w Bash (np.ls *.js).

Jeśli nie używasz domyślnej lokalizacji dla pliku konfiguracyjnegojasmine.json, wystarczy określić niestandardową lokalizację za pomocą opcjijasmine --config.

Więcej opcji CLI znajdziesz w oficjalnych dokumentach.

zrozumienie Jasmine

w tej sekcji poznamy podstawowe elementy testów Jasmine, takie jak zestawy, specyfikacje, oczekiwania, matchery i szpiegi itp.

w folderze projektu uruchom następujące polecenie, aby zainicjować nowy moduł węzła:

spowoduje to utworzenie plikupackage.json z domyślnymi informacjami:

{ "name": "jasmine-project", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": , "author": "", "license": "ISC"}

następnie utwórz plikindex.js I dodaj następujący kod:

function fibonacci(n){ if (n === 1) { return ; } else { var s = fibonacci(n - 1); s.push(s + s); return s; }}function isPrime(num){ for (let i = 2; i < num; i++) if (num % i === 0) return false; return num !== 1 && num !== 0;}function isEven(n) { return n % 2 == 0;}function isOdd(n) { return Math.abs(n % 2) == 1;}function toLowerCase(str){ return str.toLowerCase();}function toUpperCase(str){ return str.toUpperCase();}function contains(str, substring, fromIndex){ return str.indexOf(substring, fromIndex) !== -1;}function repeat(str, n){ return (new Array(n + 1)).join(str);}module.exports = { fibonacci: fibonacci, isPrime: isPrime, isEven: isEven, isOdd: isOdd, toLowerCase: toLowerCase, toUpperCase: toUpperCase, contains: contains, repeat: repeat};

apartamenty

Apartament grupuje zestaw specyfikacji lub przypadków testowych. Jest używany do testowania określonego zachowania kodu JavaScript, który jest zwykle zamknięty przez obiekt / klasę lub funkcję. Jest on tworzony przy użyciu globalnej funkcji jaśmin describe(), która pobiera dwa parametry, tytuł pakietu testowego i funkcję, która implementuje rzeczywisty kod pakietu testowego.

zacznijmy od stworzenia naszego pierwszego pakietu testowego. W folderzespec Utwórz plikMyJSUtilitiesSpec.js I dodaj:

describe("MyJSUtilities", function() { /* ... */ });

Myjsuilities to nazwa tego pakietu testowego najwyższego poziomu.

jak grupować i zagnieżdżać Pakiety

aby lepiej zorganizować i dokładnie opisać nasz zestaw testów, możemy zagnieżdżać Pakiety wewnątrz pakietu najwyższego poziomu. Na przykład, dodajmy dwa pakiety do pakietu Myjsuilities:

describe("String Utils", function() { /*...*/});describe("Math Utils", function() { /*...*/});

wewnątrz pakietu Math Utils, dodajmy również dwa zagnieżdżone Pakiety:

describe("Basic Math Utils", function() { /* ... */ }); describe("Advanced Math Utils", function() { /* ... */ });

grupujemy powiązane testy w testy dla String Utils, Basic Math Utils i Advanced Math Utils i zagnieżdżamy je wewnątrz najwyższego poziomu zestaw testowy myjsu. Spowoduje to utworzenie specyfikacji jako drzew podobnych do struktury folderów.

struktura zagnieżdżenia zostanie pokazana w raporcie, co ułatwi znalezienie nieudanych testów.

Jak wyłączyć Pakiety

możesz tymczasowo wyłączyć pakiet za pomocą funkcjixdescribe(). Ma ten sam podpis (parametry) co funkcjadescribe(), co oznacza, że możesz szybko wyłączyć istniejące pakiety, dodając do funkcjix.specyfikacje

W ramach funkcji xdescribe() będą oznaczone jako oczekujące i nie będą wykonywane w raporcie.

Specyfikacja

spec deklaruje przypadek testowy należący do zestawu testowego. Odbywa się to poprzez wywołanie funkcji globalnej jaśmin it(), która pobiera dwa parametry, tytuł spec (opisujący logikę, którą chcemy przetestować) oraz funkcję, która implementuje rzeczywisty przypadek testowy.

spec może zawierać jedno lub więcej oczekiwań. Każde oczekiwanie jest po prostu twierdzeniem, które może zwrócić true lub false. Aby spec został przekazany, wszystkie oczekiwania należące do spec muszą być true w przeciwnym razie spec nie powiedzie się.

w naszym zestawie Utils string dodaj te specyfikacje:

describe("String Utils", function() { it("should be able to lower case a string",function() { /*...*/ }); it("should be able to upper case a string",function() { /*...*/ }); it("should be able to confirm if a string contains a substring",function() { /*...*/ }); it("should be able repeat a string multiple times",function() { /*...*/ });});

w naszym zestawie Utils Basic math dodajmy kilka specyfikacji:

describe("Basic Math Utils", function() { it("should be able to tell if a number is even",function() { /*...*/ }); it("should be able to tell if a number is odd",function() { /*...*/ }); });

Dla zaawansowanych Utils Math dodajmy specyfikacje:

describe("Advanced Math Utils", function() { it("should be able to tell if a number is prime",function() { /*...*/ }); it("should be able to calculate the fibonacci of a number",function() { /*...*/ }); });

jak wykluczyć specyfikacje

podobnie jak w przypadku pakietów, można również wykluczyć poszczególne specyfikacje za pomocą funkcjixit(), która tymczasowo wyłącza specyfikacjęit() I oznacza specyfikację jako oczekującą.

oczekiwania

oczekiwania są tworzone przy użyciu funkcjiexpect(), która przyjmuje wartość zwaną rzeczywistą (mogą to być wartości, wyrażenia, zmienne, funkcje lub obiekty itp.). Oczekiwania składają się na specyfikację i są używane wraz z funkcjami matchera (poprzez łączenie łańcuchowe), aby określić, czego programista oczekuje od określonej jednostki kodu do wykonania.

funkcja dopasowująca porównuje wartość rzeczywistą (przekazaną do funkcjiexpect(), z którą jest połączona) z wartością oczekiwaną (przekazaną bezpośrednio jako parametr do dopasowującego) i zwraca true lub false, które przekazuje lub zawodzi specyfikację.

możesz połączyć funkcjęexpect() z wieloma matcherami. Aby zanegować / odwrócić wynik logiczny dowolnego matchera, możesz użyć słowa kluczowegonot przed wywołaniem matchera.

zaimplementujmy specyfikację naszego przykładu. Na razie użyjemy, użyjemy expect() z matcherem nothing(), który jest częścią wbudowanych matcherów, które zobaczymy nieco później. To przejdzie wszystkie specyfikacje, ponieważ nie oczekujemy niczego w tym momencie.

describe("MyJSUtilities", function() {describe(">String Utils", function() { it("should be able to lower case a string",function() { expect().nothing(); }); it("should be able to upper case a string",function() { expect().nothing(); }); it("should be able to confirm if a string contains a substring",function() { expect().nothing(); }); it("should be able repeat a string multiple times",function() { expect().nothing(); }); });describe("Math Utils", function() { describe("Basic Math Utils", function() { it("should be able to tell if a number is even",function() { expect().nothing(); }); it("should be able to tell if a number is odd",function() { expect().nothing(); }); }); describe("Advanced Math Utils", function() { it("should be able to tell if a number is prime",function() { expect().nothing(); }); it("should be able to calculate the fibonacci of a number",function() { expect().nothing(); }); }); });});

To jest zrzut ekranu z wynikami w tym momencie:

mamy osiem przekazanych specyfikacji i zero błędów.

Możesz użyć wbudowanych matcherów lub stworzyć własne niestandardowe matchery dla swoich konkretnych potrzeb.

wbudowane Matchery

Jasmine oferuje bogaty zestaw wbudowanych matcherów. Zobaczmy niektóre z ważnych:

  • toBe() do testowania tożsamości,
  • toBeNull() do testowania null,
  • toBeUndefined()/toBeDefined() do testowania dla undefined/not undefined,
  • toBeNaN() dla badania Nan (nie liczba)
  • toEqual() dla badania równości,
  • toBeFalsy()/toBeTruthy() do badania fałszu/prawdziwości itp.

pełną listę matcherów znajdziesz w dokumentacji.

zaimplementujmy teraz nasze specyfikacje z niektórymi z tych matcherów, gdy jest to właściwe. Najpierw zaimportuj testowane funkcje do naszego pliku MyJSUtilitiesSpec.js:

const utils = require("../index.js");

następnie rozpocznij z String Utils suite i zmień expect().nothing() z odpowiednimi oczekiwaniami.

na przykład dla pierwszej specyfikacji oczekujemy, że toLowerCase() metoda zostanie najpierw zdefiniowana, a następnie zwróci łańcuch małych liter, tj.:

it("should be able to lower case a string",function() { expect(utils.toLowerCase).toBeDefined(); expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world"); });

jest to Pełny kod dla pakietu:

describe(">String Utils", function() { it("should be able to lower case a string",function() { expect(utils.toLowerCase).toBeDefined(); expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world"); }); it("should be able to upper case a string",function() { expect(utils.toUpperCase).toBeDefined(); expect(utils.toUpperCase("hello world")).toEqual("HELLO WORLD"); }); it("should be able to confirm if a string contains a substring",function() { expect(utils.contains).toBeDefined(); expect(utils.contains("hello world","hello",0)).toBeTruthy(); }); it("should be able repeat a string multiple times",function() { expect(utils.repeat).toBeDefined(); expect(utils.repeat("hello", 3)).toEqual("hellohellohello"); }); });

niestandardowe Matchery

jaśmin zapewnia możliwość pisania niestandardowych matcherów do implementacji twierdzeń nieobjętych wbudowanymi matcherami lub po prostu w celu uczynienia testów bardziej opisowymi i czytelnymi.

Weźmy na przykład następującą specyfikację:

it("should be able to tell if a number is even",function() { expect(utils.isEven).toBeDefined(); expect(utils.isEven(2)).toBeTruthy(); expect(utils.isEven(1)).toBeFalsy(); });

Załóżmy, że metoda isEven() nie jest zaimplementowana. Jeśli uruchomimy testy, otrzymamy komunikaty takie jak Poniższy zrzut ekranu:

komunikat o błędzie, który otrzymujemy, mówi oczekiwane zdefiniowanie niezdefiniowane, co nie daje nam pojęcia o tym, co się dzieje. Uczyńmy więc ten Komunikat bardziej znaczącym w kontekście naszej domeny kodu (będzie to bardziej przydatne dla złożonych baz kodu). W tym celu stwórzmy Niestandardowy matcher.

tworzymy własne matchery za pomocą metody addMatchers(), która pobiera obiekt składający się z jednej lub wielu właściwości, które zostaną dodane jako matchery. Każda właściwość powinna dostarczać funkcję fabryczną, która przyjmuje dwa parametry: util, która ma zestaw funkcji użytkowych do użycia (patrz: matchersUtil.js) I customEqualityTesters, która musi zostać przekazana, jeśli util.equals zostanie wywołany i powinien zwrócić obiekt z funkcją compare, która zostanie wywołana w celu sprawdzenia oczekiwanego.

musimy zarejestrować Niestandardowy matcher przed wykonaniem każdej specyfikacji za pomocą metody beforeEach() :

describe("/Basic Math Utils", function () {beforeEach(function () {jasmine.addMatchers({hasEvenMethod: function (util, customEqualityTesters) {return {compare: function (actual, expected) {var result = { pass: utils.isEven !== undefined };if (result.pass) {result.message = "Expected isEven() to be not defined."}else {result.message = "Expected isEven() to be defined."}return result;}}}});});/*...*/});

możemy wtedy użyć niestandardowego matchera zamiastexpect(utils.isEven).toBeDefined():

expect().hasEvenMethod();

To da nam lepszy komunikat o błędzie:

używanie beforeeach() i aftereach ()

do inicjalizacji i czyszczenia specyfikacji jaśmin zapewnia dwie globalne funkcje,beforeEach() IafterEach():

  • funkcjabeforeEach jest wywoływana raz przed każdą specyfikacją w pakiecie, w którym jest wywoływana.
  • funkcjaafterEach jest wywoływana raz po każdej specyfikacji w pakiecie, w którym jest wywoływana.

na przykład, jeśli chcesz użyć dowolnych zmiennych w swoim zestawie testowym, możesz po prostu zadeklarować je na początku funkcjidescribe() I umieścić dowolny kod inicjalizacji lub instancji wewnątrz funkcjibeforeEach(). Na koniec możesz użyć funkcjiafterEach(), aby zresetować zmienne po każdej specyfikacji, dzięki czemu możesz mieć czyste Testowanie jednostek bez konieczności powtarzania kodu inicjalizacji i czyszczenia dla każdej specyfikacji.

funkcjabeforeEach() jest również doskonale połączona z wieloma interfejsami API jaśmin, takimi jakaddMatchers() metoda tworzenia własnych matcherów lub również z funkcjądone(), aby czekać na operacje asynchroniczne przed kontynuowaniem testowania.

niepowodzenie testu

możesz wymusić niepowodzenie testu za pomocą globalnej metody fail() dostępnej w Jaśminie. Na przykład:

it("should explicitly fail", function () { fail('Forced to fail'); });

powinieneś otrzymać następujący błąd:

testowanie WYJĄTKÓW

podczas testowania jednostki kod może zgłaszać błędy i wyjątki, więc może być konieczne przetestowanie tych scenariuszy. Jaśmin udostępnia dopasowania toThrow() I toThrowError(), aby sprawdzić, czy wyjątek został zgłoszony, lub aby sprawdzić, czy dany wyjątek został zgłoszony.

na przykład, jeśli mamy funkcję, która wyrzuca wyjątek TypeError :

function throwsError() { throw new TypeError("A type error"); }

Możesz napisać specyfikację, która ma sprawdzić, czy został zgłoszony wyjątek:

it('it should throw an exception', function () { expect(throwsError).toThrow(); });

lub możesz również użyć testu dla konkretnego TypeError wyjątek:

it('it should throw a TypeError', function () { expect(throwsError).toThrowError(TypeError); });

zrozumienie szpiegów

najczęściej metody zależą od innych metod. Oznacza to, że podczas testowania metody może również skończyć się testowaniem jej zależności. Nie jest to zalecane w testowaniu, tzn. musisz upewnić się, że testujesz czystą funkcję, izolując metodę i sprawdzając, jak zachowuje się ona, biorąc pod uwagę zestaw wejść.

Jasmine dostarcza szpiegów, których można użyć do szpiegowania/nasłuchiwania wywołań metod na obiektach i raportowania, czy metoda została wywołana oraz z jakim kontekstem i argumentami.

jaśmin udostępnia dwa sposoby szpiegowania wywołań metod: używając spyOn() lub createSpy().

można użyć spyOn(), gdy metoda już istnieje w obiekcie, w przeciwnym razie należy użyć jasmine.createSpy(), która zwraca nową funkcję.

domyślnie Szpieg raportuje tylko wtedy, gdy połączenie zostało wykonane bez wywołania przez funkcję szpiegującą (i.e funkcja przestanie być wykonywana), ale możesz zmienić domyślne zachowanie za pomocą następujących metod:

  • and.callThrough(): wywołanie przez oryginalną funkcję,
  • and.returnValue(value): zwróć określoną wartość,
  • and.callFake(fn): wywołanie funkcji funkcja fałszywa zamiast oryginalnej,
  • and.throwError(err): wyrzuca błąd,
  • and.stub(): resetuje domyślne zachowanie stubbingu.

możesz użyć szpiega do zbierania statystyk czasu pracy funkcji szpiegowanej, na przykład jeśli chcesz wiedzieć, ile razy twoja funkcja została wywołana.

powiedzmy, że chcemy się upewnić, że naszatoUpperCase() metoda wykorzystuje wbudowanąString.toUpperCase() metoda, musimy po prostu szpiegować String.toUpperCase() używając:

it("should be able to upper case a string", function () { 
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase') 
expect(utils.toUpperCase).toBeDefined(); expect(utils.toUpperCase("hello world")).toEqual("HELLO WORLD"); expect(String.prototype.toUpperCase).toHaveBeenCalled(); expect(spytoUpperCase.calls.count()).toEqual(1); });

test nie powiódł się z powodu drugiego oczekiwania, ponieważ utils.toUpperCase("hello world") zwrócił Undefined zamiast oczekiwanego Hello World. Dzieje się tak, ponieważ, jak wspomnieliśmy wcześniej, po utworzeniu szpiega na toUpperCase(), metoda nie jest wykonywana. Musimy zmienić to domyślne zachowanie, wywołując callThrough():

należy pamiętać, że funkcjaspy domyślnie zastępuje funkcję szpiegowaną stubem. Jeśli chcesz wywołać oryginalną funkcję, możesz dodać .and.callThrough() do obiektu spy

var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callThrough();

teraz wszystkie oczekiwania przechodzą.

Możesz również użyćand.callFake() luband.returnValue(), aby sfałszować funkcję szpiegowaną lub po prostu wartość zwracaną, jeśli nie chcesz wywoływać przez rzeczywistą funkcję:

var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.returnValue("HELLO WORLD"); 
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callFake(function(){ return "HELLO WORLD"; });

teraz, jeśli nie będziemy używać wbudowanegoString.toUpperCase() we własnej implementacjiutils.toUpperCase(), otrzymamy następujące błędy:

ie udało się spełnić dwóch oczekiwańexpect(String.prototype.toUpperCase).toHaveBeenCalled()

oba oczekiwania expect(String.prototype.toUpperCase).toHaveBeenCalled()expect(spytoUpperCase.calls.count()).toEqual(1) nie powiodły się.

Jak radzić sobie z Asynchronicznością w Jaśminie

Jeśli testowany kod zawiera operacje asynchroniczne, potrzebujesz sposobu, aby poinformować jaśmin o zakończeniu operacji asynchronicznych.

domyślnie jaśmin czeka na zakończenie dowolnej operacji asynchronicznej, zdefiniowanej przez wywołanie zwrotne, obietnicę lub słowo kluczowe async. Jeśli jaśmin znajdzie słowo kluczowe zwrotne, obietnicę lub asynchroniczne w jednej z tych funkcji: beforeEachafterEachbeforeAllafterAll I it będzie czekać na wykonanie asynchroniczne przed przejściem do następnej operacji.

używanie done() z beforeEach () / it ()..

weźmy przykładsimulateAsyncOp(), który symuluje operację asynchroniczną za pomocąsetTimeout(). W rzeczywistym świecie może to być żądanie Ajax lub inna podobna rzecz, która dzieje się asynchronicznie:

function simulateAsyncOp(callback){ 
setTimeout(function () { callback(); }, 2000); }

aby przetestować tę funkcję, możemy użyć funkcji beforeEach() ze specjalnym done() callback. Nasz kod musi wywołać done(), aby powiedzieć Jaśminowi, że operacja asynchroniczna została zakończona:

describe("/Async Op", function () {var asyncOpCompleted = false;beforeEach(function (done) {utils.simulateAsyncOp(function(){ asyncOpCompleted = true; done();});});it("should be able to tell if the async call has completed", function () { expect(asyncOpCompleted).toEqual(true);});});

możemy szybko zauważyć wadę tej metody, więc musimy napisać nasz kod, aby zaakceptować done() callback. W naszym przypadku nie zakodowaliśmy metody done() w naszym simulateAsyncOp(fn), ale dostarczyliśmy parametr wywołania zwrotnego, aby móc wywołać done().

Używanie funkcji Promises

Jeśli nie chcesz tworzyć kodu zależnego od sposobu pisania testu, możesz użyć funkcji promise i wywołać wywołanie zwrotnedone(), gdy obietnica zostanie rozwiązana. Albo jeszcze lepiej, w Jaśminie 2.7+, jeśli twój kod zwróci Promise, jaśmin będzie czekał, aż zostanie rozwiązany lub odrzucony przed wykonaniem następnego kodu.

używając asynchronicznego/oczekującego

jaśmin 2.7+ obsługujeasync Iawait wywołania w specyfikacji. Zwalnia to Użytkownika z umieszczania twierdzeń w bloku .then() lub .catch().

it("should work with async/await", async () => { let completed = false; completed = await utils.simulateAsyncOp(); expect(completed).toEqual(true); });

jest to implementacja simulateAsyncOp:

function simulateAsyncOp() { 
return new Promise(resolve => { setTimeout(() => { resolve(true); }, 1000); }); }

Korzystanie z zegara jaśmin

zegar jaśmin służy do testowania kodu asynchronicznego zależnego od funkcji czasowych, takich jaksetTimeout() w ten sam sposób testujemy kod synchroniczny, wyśmiewając API oparte na czasie za pomocą niestandardowych metod. W ten sposób można wykonywać testowane funkcje synchronicznie, sterując lub ręcznie przesuwając zegar.

możesz zainstalować zegar jaśmin, wywołując funkcjęjasmine.clock().install w swojej specyfikacji lub pakiecie.

Po użyciu zegara należy go odinstalować, aby przywrócić oryginalne funkcje.

za pomocą Jasmine clock możesz sterować funkcjami JavaScript setTimeout lub setInterval, zaznaczając Zegar, aby przyspieszyć czas za pomocą funkcji jasmine.clock().tick, która pobiera liczbę milisekund, z którymi możesz się poruszać.

Możesz również użyć zegara Jasmine, aby wyśmiać bieżącą datę.

beforeEach(function () {jasmine.clock().install();});afterEach(function() {jasmine.clock().uninstall();});it("should call the asynchronous operation synchronously", function() {var completed = false;utils.simulateAsyncOp(function(){completed = true;});expect(completed).toEqual(false);jasmine.clock().tick(1001);expect(completed).toEqual(true);});

jest to funkcjasimulateAsyncOp :

function simulateAsyncOp(callback){ 
setTimeout(function () { callback(); }, 1000); }

jeśli nie podałeś czasu dla funkcjimockDate, użyje bieżącej daty.

Obsługa błędów

Jeśli Twój kod asynchroniczny nie powiedzie się z powodu jakiegoś błędu, chcesz, aby specyfikacje zawiodły poprawnie. Począwszy od jaśmin 2.6 + wszelkie nieobsługiwane błędy są wysyłane do aktualnie wykonywanej specyfikacji.

Jasmine zapewnia również sposób, którego możesz użyć, jeśli chcesz wyraźnie zawieść specyfikacje:

  • za pomocą done()callback z beforeEach()wywołującdone.fail(err) metoda,
  • po prostu przekazując błąd dodone(err) callback (jaśmin 3+),
  • wywołanie reject()metody Promise.

podsumowanie

w tym przewodniku przedstawiliśmy jaśmin i zobaczyliśmy, jak zacząć używać jaśmin do jednostkowego testowania kodu JavaScript. Dzięki za przeczytanie!

Ten artykuł został pierwotnie opublikowany w techiediaries.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *