Jasmine is de meest populaire js bibliotheek voor unit testing web apps. In deze tutorial, ontworpen voor beginners, presenteren we u een snelle en complete gids voor het testen met Jasmine.
u maakt kennis met Jasmine, een populair gedraggestuurd testkader voor JavaScript. We zullen ook een eenvoudig praktisch voorbeeld zien over het schrijven van unit tests met Jasmine die u kunnen helpen om gemakkelijk te controleren op bugs in uw code.
in het kort zullen we zien hoe je testsuites, specificaties en verwachtingen kunt schrijven en hoe je ingebouwde Jasmine matchers kunt toepassen of je eigen aangepaste matchers kunt bouwen
we zullen ook zien hoe je suites kunt groeperen om je tests te organiseren voor complexere codebasissen.
de introductie van Jasmine
Jasmine is een zeer populaire JavaScript gedrag-gedreven ontwikkeling (In BDD, schrijf je testen voordat het schrijven van de werkelijke code) kader voor unit testen van JavaScript-toepassingen. Het biedt hulpprogramma ‘ s die kunnen worden gebruikt om geautomatiseerde tests uit te voeren voor zowel synchrone als asynchrone code.
Jasmine heeft veel functies zoals:
- Het is snel en heeft lage overhead en geen externe afhankelijkheden.
- het is een bibliotheek met batterijen en biedt alles wat u nodig hebt om uw code te testen.
- het is beschikbaar voor zowel Node als de browser.
- het kan gebruikt worden met andere talen zoals Python en Ruby.
- Het vereist geen DOM.
- Het biedt een schone en gemakkelijk te begrijpen syntaxis en ook een rijke en rechttoe rechtaan API.
- We kunnen natuurlijke taal gebruiken om de tests en de verwachte resultaten te beschrijven.
Jasmine is een open source tool die beschikbaar is onder de permissive MIT licentie. Vanaf dit schrijven van de nieuwste belangrijke versie is Jasmine 3.0 die nieuwe functies en een aantal brekende veranderingen biedt. De 2.99 release van Jasmine zal verschillende deprecation waarschuwingen voor suites die ander gedrag in versie 3.0, waardoor het gemakkelijk voor ontwikkelaars om te migreren naar de nieuwe versie.
u kunt lezen over de nieuwe functies en het breken van wijzigingen van dit document.
Jasmine gebruiken
U kunt Jasmine op veel verschillende manieren gebruiken:
- op de oude manier door zowel de Jasmine core als uw testbestanden op te nemen met behulp van een
<scri
pt> tag, - als een CLI-tool met Node.js,
- als een bibliotheek in Node.js,
- als onderdeel van een bouwsysteem zoals Gulp.js of Grunt.js via grunt-contrib-jasmine en gulp-jasmine-browser
U kunt Jasmine ook gebruiken voor het testen van uw Python-code met jasmine-py die kan worden geïnstalleerd vanaf PyPI met behulp van het pip install jasmine
Commando. Dit pakket bevat zowel een webserver die dient en voert een Jasmine suite voor uw project en een CLI script voor het uitvoeren van tests en continue integraties.
Jasmine is ook beschikbaar voor Ruby-projecten via jasmine-gem dat kan worden geïnstalleerd door gem 'jasmine'
aan uw Gemfile toe te voegen en bundle install
uit te voeren. Het bevat een server voor het serveren en uitvoeren van tests, een CLI script en ook generatoren voor Ruby on Rails projecten.
laten we ons nu concentreren op het gebruik van Jasmine met JavaScript:
met behulp van Standalone Jasmine
begin met het downloaden van de nieuwste versie van Jasmine van de releases pagina.
pak dan gewoon het zip-bestand uit, bij voorkeur in een map in het project dat u wilt testen.
de map bevat een aantal standaardbestanden en mappen:
/src
: bevat de bronbestanden die u wilt testen. Dit kan worden verwijderd als je al de map van je project hebt ingesteld of kan ook worden gebruikt indien nodig voor het hosten van je broncode.
/lib
: bevat de Core Jasmine-bestanden.
/spec
: bevat de tests die u gaat schrijven.
SpecRunner.html
: dit bestand wordt gebruikt als testrunner. U voert uw specificaties door simpelweg de lancering van dit bestand.
Dit is de inhoud van een standaard SpecRunner.html
bestand:
<!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>
onthoud dat u de bestanden uit de /src
en /spec
moet wijzigen om uw werkelijke bron en test te bevatten dossiers.
Jasmine gebruiken als bibliotheek
U kunt Jasmine ook gebruiken als bibliotheek in uw project. Bijvoorbeeld de volgende code importeert en voert Jasmine uit:
var Jasmine = require('jasmine');var jasmine = new Jasmine();jasmine.loadConfigFile('spec/support/jasmine.json');jasmine.execute();
eerst vereisen we/import Jasmine en gebruiken we de loadConfigFile()
methode om het configuratiebestand te laden dat beschikbaar is vanuit spec/support/jasmine.json
pad en tenslotte voeren we Jasmine uit.
Jasmine gebruiken via de CLI
U kunt ook Jasmine van de CLI gebruiken, waarmee u eenvoudig Jasmine-tests kunt uitvoeren en standaard de resultaten in de terminal kunt uitvoeren.
We zullen deze aanpak volgen om onze voorbeeldtesten in deze gids uit te voeren, dus voer eerst het volgende commando uit om Jasmine globaal te installeren:
npm install -g jasmine
Het kan nodig zijn sudo uit te voeren voor het installeren van NPM-pakketten globaal, afhankelijk van uw NPM-configuratie.
Maak nu een map aan voor uw project en navigeer erin:
$ mkdir jasmine-project $ cd jasmine-project
voer vervolgens het volgende commando uit om uw project voor Jasmine te initialiseren:
Dit commando maakt eenvoudig een spec-map en een JSON-configuratiebestand. Dit is de uitvoer van dir
Commando:
.└── spec └── support └── jasmine.json2 directories, 1 file
Dit is de inhoud van een standaard jasmine.json
bestand:
{ "spec_dir": "spec", "spec_files": pec.js" ], "helpers": , "stopSpecOnExpectationFailure": false, "random": true}
-
spec_dir
: geeft aan waar Jasmine naar testbestanden zoekt. -
spec_files
: specificeert de patronen van testbestanden, standaard alle JS-bestanden die eindigen met Spec of spec-strings. -
helpers
: geeft aan waar Jasmine naar hulpbestanden zoekt. Helper bestanden worden uitgevoerd voordat specs en kunnen worden gebruikt om aangepaste matchers definiëren. -
stopSpecOnExpectationFailure
: wanneer ingesteld op true stopt onmiddellijk een specificatie over de eerste mislukking van een verwachting (kan worden gebruikt als een CLI-optie via--stop-on-failure
). -
random
: indien ingesteld op true zal Jasmine de testcases pseudo-willekeurig uitvoeren (kan worden gebruikt als een CLI-optie via--random
).
despec_files
enhelpers
arrays kunnen ook Glob-patronen bevatten (dankzij het pakket node-glob) voor het specificeren van bestandspaden die patronen zijn die u gewoonlijk gebruikt om een set bestanden op te geven wanneer u in Bash werkt (bijvoorbeeldls *.js
).
Als u de standaardlocatie niet gebruikt voor het jasmine.json
configuratiebestand, hoeft u alleen de aangepaste locatie op te geven via de optie jasmine --config
.
u kunt meer CLI-opties vinden in de officiële documenten.
Jasmine begrijpen
In deze sectie leren we over de basiselementen van Jasmine testen zoals suites, SPECIFICATIES, verwachtingen, matchers en spies, etc.
voer in de map van uw project het volgende commando uit om een nieuwe Knooppuntmodule te initialiseren:
Dit zal een package.json
bestand met standaard informatie aanmaken:
{ "name": "jasmine-project", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": , "author": "", "license": "ISC"}
volgende, Maak een index.js
bestand en voeg de volgende code toe:
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};
Suites
een suite groepeert een set specificaties of testcases. Het wordt gebruikt om een specifiek gedrag van de JavaScript-code die meestal is ingekapseld door een object/klasse of een functie te testen. Het is gemaakt met behulp van de Jasmine global functie describe()
die twee parameters neemt, de titel van de test suite en een functie die de eigenlijke code van de test suite implementeert.
laten we beginnen met het maken van onze eerste test suite. Maak in de map spec
een MyJSUtilitiesSpec.js
bestand aan en voeg toe:
describe("MyJSUtilities", function() { /* ... */ });
Mijnjsutilities is de naam van deze top-level test suite.
hoe Suites te groeperen en te nestelen
voor een betere organisatie en accurate beschrijving van onze set testen kunnen we suites nestelen in de top-level suite. Bijvoorbeeld, laten we twee suites toevoegen aan de myjsutilities suite:
describe("String Utils", function() { /*...*/});describe("Math Utils", function() { /*...*/});
binnen de Math Utils suite, laten we ook twee geneste suites toevoegen:
describe("Basic Math Utils", function() { /* ... */ }); describe("Advanced Math Utils", function() { /* ... */ });
we groeperen verwante tests in tests voor String Utils, Basic Math Utils en Advanced Math Utils en nesten ze in de top-level test suite mijnjsutilities. Dit zal uw specificaties samen te stellen als bomen vergelijkbaar met een structuur van mappen.
de nesting structuur zal getoond worden op het rapport wat het gemakkelijk maakt voor u om falende tests te vinden.
Suites uitsluiten
U kunt een suite tijdelijk uitschakelen met de functie xdescribe()
. Het heeft dezelfde signature (parameters) als een describe()
functie, wat betekent dat u snel uw bestaande suites kunt uitschakelen door simpelweg een x
aan de functie toe te voegen.
Specs binnen eenxdescribe()
functie zal worden gemarkeerd in afwachting en niet uitgevoerd in het rapport.
Specs
een spec verklaart een testcase die tot een testsuite behoort. Dit wordt gedaan door de Jasmine global functie it()
aan te roepen die twee parameters neemt, de titel van de spec (die de logica beschrijft die we willen testen) en een functie die de eigenlijke testcase implementeert.
een specificatie kan één of meer verwachtingen bevatten. Elke verwachting is simpelweg een bewering die true
of false
kan geven. Om de spec door te geven, moeten alle verwachtingen die tot de spec behoren true
zijn, anders faalt de spec.
binnen onze String Utils suite, voeg deze specs toe:
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() { /*...*/ });});
binnen onze Basic Math Utils suite laten we enkele specs toevoegen:
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() { /*...*/ }); });
voor de geavanceerde wiskunde Utils, laten we de specs toevoegen:
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() { /*...*/ }); });
hoe Specs uit te sluiten
net als suites kunt u ook individuele specs uitsluiten met behulp van de functie xit()
die tijdelijk de it()
spec uitschakelt en de spec als in behandeling markeert.
verwachtingen
verwachtingen worden gemaakt met behulp van de functieexpect()
die een waarde aanneemt die de werkelijke wordt genoemd (dit kunnen waarden, expressies, variabelen, functies of objecten etc.). Verwachtingen componeren de spec en worden gebruikt samen met matcher functies (via chaining) om te bepalen wat de ontwikkelaar verwacht van een specifieke eenheid code uit te voeren.
een matcher-functie vergelijkt tussen een werkelijke waarde (doorgegeven aan de expect()
functie waarmee het is geketend) en een verwachte waarde (direct doorgegeven als een parameter aan de matcher) en geeft true of false terug die de spec passeert of faalt.
u kunt de functie expect()
chain met meerdere matchers. Om het Booleaanse resultaat van een matcher te ontkennen/omkeren, kunt u het not
sleutelwoord gebruiken voordat u de matcher aanroept.
laten we de specificaties van ons voorbeeld implementeren. Voor nu zullen we expect()
gebruiken met de nothing()
matcher die deel uitmaakt van de ingebouwde matchers die we even later zullen zien. Dit zal alle specificaties passeren aangezien we niets verwachten op dit punt.
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(); }); }); });});
Dit is een screenshot van de resultaten op dit punt:
we hebben acht opgegeven specificaties en nul fouten.
u kunt ingebouwde matchers gebruiken of ook uw eigen aangepaste matchers maken voor uw specifieke behoeften.
ingebouwde Matchers
Jasmine biedt een rijke set ingebouwde matchers. Laten we eens een aantal van de belangrijkste zien:
-
toBe()
voor het testen van identiteit, -
toBeNull()
voor het testen van voornull
, -
toBeUndefined()/toBeDefined()
voor het testen van voorundefined
/nietundefined
, -
toBeNaN()
voor het testen van NaN (not A Number) -
toEqual()
voor het testen van gelijkheid, -
toBeFalsy()/toBeTruthy()
voor het testen van valsheid/waarheid enz.
u kunt de volledige lijst van matchers uit de docs vinden.
laten we nu onze specs implementeren met een aantal van deze matchers indien van toepassing. Importeer eerst de functies die we testen in ons MyJSUtilitiesSpec.js
bestand:
const utils = require("../index.js");
volgende, begin met de String Utils suite en verander expect().nothing()
met de juiste verwachtingen.
bijvoorbeeld voor de eerste specificatie verwachten we dat de toLowerCase()
methode eerst gedefinieerd wordt en ten tweede een tekenreeks met kleine letters retourneert, d.w.z.:
it("should be able to lower case a string",function() { expect(utils.toLowerCase).toBeDefined(); expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world"); });
Dit is de volledige code voor de suite:
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"); }); });
aangepaste Matchers
Jasmine biedt de mogelijkheid om aangepaste matchers te schrijven voor het implementeren van beweringen die niet door de ingebouwde matchers worden gedekt of gewoon om tests beschrijvend en leesbaarder te maken.
bijvoorbeeld, neem de volgende specificatie:
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(); });
stel dat de isEven()
methode niet is geïmplementeerd. Als we de tests uitvoeren, krijgen we berichten zoals de volgende schermafbeelding:
Het foutbericht dat we krijgen, zegt dat er een ongedefinieerde verwachting moet worden gedefinieerd, wat ons geen idee geeft van wat er gebeurt. Dus laten we dit bericht zinvoller maken in de context van ons code Domein (dit zal nuttiger zijn voor complexe code bases). Voor deze kwestie, laten we een aangepaste matcher maken.
We maken aangepaste matchers met behulp van deaddMatchers()
methode die een object neemt dat bestaat uit een of meerdere eigenschappen die als matchers zullen worden toegevoegd. Elke eigenschap moet een fabrieksfunctie hebben die twee parameters neemt: util
, die een set utility functies heeft die matchers moeten gebruiken (zie: matchersUtil.js
) en customEqualityTesters
die moet worden doorgegeven als util.equals
wordt aangeroepen, en een object met een compare
functie die zal worden aangeroepen om de verwachting te controleren.
We moeten de aangepaste matcher registreren voordat elke specificatie wordt uitgevoerd met behulp van de beforeEach()
methode:
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;}}}});});/*...*/});
We kunnen dan gebruik maken van de aangepaste matcher in plaats van de expect(utils.isEven).toBeDefined()
:
expect().hasEvenMethod();
Dit zal ons een beter fout bericht:
met Behulp van de beforeEach() en afterEach()
Voor het initialiseren en reinigen van je bril, Jasmijn biedt twee algemene functies beforeEach()
en afterEach()
:
- De
beforeEach
functie is aangeroepen voor elke specificatie in de suite waar het heet. - de functie
afterEach
wordt eenmaal aangeroepen na elke specificatie in de suite waar het wordt aangeroepen.
bijvoorbeeld, als u variabelen wilt gebruiken in uw test suite, kunt u ze eenvoudig declareren in het begin van de describe()
functie en elke initialisatie-of instantiatiecode in een beforeEach()
functie plaatsen. Tot slot kunt u de functie afterEach()
gebruiken om de variabelen na elke specificatie te resetten, zodat u pure unit testen kunt uitvoeren zonder de noodzaak om initialisatie en opschooncode voor elke specificatie te herhalen.
de beforeEach()
functie is ook perfect gecombineerd met veel Jasmine API ‘ s zoals de addMatchers()
methode om aangepaste matchers aan te maken of ook met de done()
functie om te wachten op asynchrone bewerkingen voordat verder wordt getest.
falend voor een Test
u kunt een test forceren te mislukken met behulp van de Globale fail()
methode beschikbaar in Jasmine. Bijvoorbeeld:
it("should explicitly fail", function () { fail('Forced to fail'); });
u krijgt de volgende fout:
testen voor uitzonderingen
wanneer u unit-testen van uw code, fouten en uitzonderingen mogelijk gegooid, dus moet u misschien testen voor deze scenario ‘ s. Jasmine levert detoThrow()
entoThrowError()
matchers om respectievelijk te testen wanneer een uitzondering wordt gegooid of om te testen voor een specifieke uitzondering.
bijvoorbeeld als we een functie hebben die een TypeError
uitzondering gooit:
function throwsError() { throw new TypeError("A type error"); }
u kunt een specificatie schrijven die moet worden getest als er een uitzondering wordt gemaakt:
it('it should throw an exception', function () { expect(throwsError).toThrow(); });
of u kunt ook test gebruiken voor de specifieke TypeError
uitzondering:
it('it should throw a TypeError', function () { expect(throwsError).toThrowError(TypeError); });
spies begrijpen
vaak zijn methoden afhankelijk van andere methoden. Dit betekent dat wanneer je een methode test, je kan ook eindigen met het testen van de afhankelijkheden. Dit wordt niet aanbevolen bij het testen dat wil zeggen dat je ervoor moet zorgen dat je de pure functie test door de methode te isoleren en te zien hoe het zich gedraagt gegeven een set van ingangen.
Jasmine biedt spies die kunnen worden gebruikt om methodeaanroepen op objecten te bespioneren/beluisteren en te rapporteren of een methode wordt aangeroepen en met welke context en argumenten.
Jasmine biedt twee manieren om methodeaanroepen te bespioneren: met behulp van de spyOn()
of de createSpy()
methoden.
u kunt spyOn()
gebruiken als de methode al bestaat op het object, anders moet u jasmine.createSpy()
gebruiken die een nieuwe functie retourneert.
standaard zal een spy alleen rapporteren als een oproep werd gedaan zonder te bellen via de spied functie (i.e de functie zal stoppen met het uitvoeren van), maar u kunt het wijzigen van de standaard gedrag met behulp van deze methoden:
-
and.callThrough()
: bellen via de oorspronkelijke functie -
and.returnValue(value)
: de terugkeer van de opgegeven waarde, -
and.callFake(fn)
: bel de nep-functie in plaats van de originele, -
and.throwError(err)
: gooi een fout, -
and.stub()
: zet de standaard stoten gedrag.
u kunt een spy gebruiken om runtime statistieken te verzamelen over de spied functie, bijvoorbeeld als u wilt weten hoe vaak uw functie is aangeroepen.
zeggen dat we ervoor willen zorgen dat onzetoUpperCase()
methode gebruik maakt van de ingebouwde String.toUpperCase()
methode, we moeten gewoon spy on String.toUpperCase()
met behulp van:
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); });
De test is mislukt vanwege de tweede verwachting, omdat utils.toUpperCase("hello world")
undefined geretourneerd in plaats van de verwachte HALLO WERELD. Dat komt omdat, zoals we al zeiden, eerder na het aanmaken van de spy Op toUpperCase()
, de methode niet wordt uitgevoerd. We moeten dit standaardgedrag wijzigen door callThrough()
aan te roepen:
merk op dat een
spy
functie de spied functie standaard vervangt door een stub. Als u de oorspronkelijke functie wilt aanroepen, kunt u.and.callThrough()
toevoegen aan uwspy
object.
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callThrough();
nu gaan alle verwachtingen voorbij.
u kunt ook and.callFake()
of and.returnValue()
gebruiken om de spied on-functie te faken of alleen de retourwaarde als u niet via de werkelijke functie belt:
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.returnValue("HELLO WORLD");
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callFake(function(){ return "HELLO WORLD"; });
Nu, als we eindigen niet met behulp van de ingebouwde String.toUpperCase()
in onze eigen utils.toUpperCase()
implementatie, krijgen we van deze fouten:
De twee verwachtingen expect(String.prototype.toUpperCase).toHaveBeenCalled()
expect(spytoUpperCase.calls.count()).toEqual(1)
hebben gefaald.
hoe om te gaan met Asynchroniciteit in Jasmine
als de code die u test asynchrone bewerkingen bevat, moet u een manier vinden om Jasmine te laten weten wanneer de asynchrone bewerkingen zijn voltooid.
standaard wacht Jasmine op een asynchrone bewerking, gedefinieerd door een callback, promise of het async
sleutelwoord, om te worden voltooid. Als Jasmine een callback, promise of async sleutelwoord vindt in een van deze functies: beforeEach
afterEach
beforeAll
afterAll
, en it
het zal wacht tot de asynchrone wordt gedaan voordat u verder gaat met de volgende bewerking.
met behulp van done () met beforeach ()/it ()..
neem ons voorbeeld simulateAsyncOp()
die een asynchrone operatie simuleert met setTimeout()
. In een echt scenario kan dit een Ajax-verzoek zijn of iets dergelijks dat asynchroon gebeurt:
function simulateAsyncOp(callback){
setTimeout(function () { callback(); }, 2000); }
om deze functie te testen kunnen we de beforeEach()
functie gebruiken met de speciale done()
callback. Onze code moet done()
aanroepen om Jasmine te vertellen dat de asynchrone bewerking is voltooid:
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);});});
We kunnen snel een nadeel van deze methode opmerken, dus we moeten onze code schrijven om de done()
callback te accepteren. In ons geval hebben we de done()
methode niet hardcodeerd in onze simulateAsyncOp(fn)
maar we hebben een callback parameter gegeven om done()
te kunnen aanroepen.
met behulp van Promises
Als u geen code wilt maken die afhangt van hoe u uw test schrijft, kunt u in plaats daarvan een promise gebruiken en de done()
callback aanroepen wanneer de promise is opgelost. Of beter nog, in Jasmine 2.7+, als je code een Promise
retourneert, zal Jasmine wachten tot het is opgelost of afgewezen voordat de volgende code wordt uitgevoerd.
met behulp van async/wait
Jasmine 2.7 + ondersteunt async
en await
aanroepen in SPECIFICATIES. Dit ontlast u van het plaatsen van asserts in een .then()
of .catch()
blok.
it("should work with async/await", async () => { let completed = false; completed = await utils.simulateAsyncOp(); expect(completed).toEqual(true); });
Dit is de implementatie van simulateAsyncOp
:
function simulateAsyncOp() {
return new Promise(resolve => { setTimeout(() => { resolve(true); }, 1000); }); }
met Jasmine Clock
De Jasmine clock wordt gebruikt om asynchrone code te testen die afhankelijk is van tijdfuncties zoals setTimeout()
op dezelfde manier testen we synchrone code door tijdgebaseerde API ‘ s met aangepaste methoden te bespotten. Op deze manier kunt u de geteste functies synchroon uitvoeren door de klok te bedienen of handmatig te verplaatsen.
U kunt de Jasmine clock installeren door de functie jasmine.clock().install
aan te roepen in uw spec of suite.
na het gebruik van de klok, moet u deze verwijderen om de oorspronkelijke functies te herstellen.
met Jasmine clock kunt u de JavaScript setTimeout
of setInterval
functies beheren door de klok aan te vinken om door te gaan in de tijd met behulp van de jasmine.clock().tick
functie, die het aantal milliseconden neemt waarmee u kunt bewegen.
U kunt de Jasmine Clock ook gebruiken om de huidige datum te bespotten.
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);});
Dit is de simulateAsyncOp
functie:
function simulateAsyncOp(callback){
setTimeout(function () { callback(); }, 1000); }
indien u geen tijd hebt opgegeven voor de functie
mockDate
, wordt de huidige datum gebruikt.
Handling Errors
als uw asynchrone code faalt als gevolg van een fout, wilt u dat uw specificaties correct falen. Beginnend met Jasmine 2.6+ alle niet-behandelde fouten worden verzonden naar de momenteel uitgevoerde spec.
Jasmine biedt ook een manier die u kunt gebruiken als u expliciet moet falen bij uw specificaties:
- gebruikmakend van de
done()
callback metbeforeEach()
door dedone.fail(err)
methode aan te roepen, - gewoon een fout doorgeven aan de
done(err)
callback (Jasmine 3+), - aanroep van de
reject()
methode van eenPromise
.
conclusie
in deze gids hebben we Jasmine geïntroduceerd en gezien hoe we aan de slag kunnen met Jasmine om uw JavaScript-code te testen. Bedankt voor het lezen!
Dit artikel is oorspronkelijk geplaatst in techiediaries.