Jasmine è la libreria JS più popolare per le applicazioni web unit testing. In questo tutorial, progettato per i principianti, ti presenteremo una guida rapida e completa ai test con Jasmine.
Verrai introdotto a Jasmine, un popolare framework di test basato sul comportamento per JavaScript. Vedremo anche un semplice esempio pratico su come scrivere unit test con Jasmine che può aiutarti a controllare facilmente i bug nel tuo codice.
In poche parole, vedremo come scrivere suite di test, le specifiche e le aspettative e come applicare built-in Jasmine matcher o costruire i propri matchers personalizzati
Vedremo anche come è possibile raggruppare suite per il bene di organizzare i test per basi di codice più complesse.
Presentazione di Jasmine
Jasmine è un framework di sviluppo basato sul comportamento JavaScript molto popolare (in BDD, si scrivono test prima di scrivere codice effettivo) per le applicazioni JavaScript unit testing. Fornisce utilità che possono essere utilizzate per eseguire test automatici per il codice sincrono e asincrono.
Jasmine ha molte caratteristiche come:
- È veloce e ha un basso sovraccarico e nessuna dipendenza esterna.
- Si tratta di una libreria batterie incluse e offre tutto il necessario per testare il codice.
- È disponibile sia per il nodo che per il browser.
- Può essere utilizzato con altri linguaggi come Python e Ruby.
- Non richiede il DOM.
- Fornisce una sintassi pulita e facile da capire e anche un’API ricca e diretta.
- Possiamo usare il linguaggio naturale per descrivere i test e i risultati attesi.
Jasmine è uno strumento open source disponibile sotto la licenza MIT permissiva. Al momento della stesura di questo articolo l’ultima versione principale è Jasmine 3.0 che fornisce nuove funzionalità e alcune modifiche di rottura. La versione 2.99 di Jasmine fornirà diversi avvisi di deprecazione per le suite che hanno un comportamento diverso nella versione 3.0 che renderà più facile per gli sviluppatori migrare alla nuova versione.
È possibile leggere le nuove funzionalità e le modifiche di rottura da questo documento.
Usando Jasmine
Puoi usare Jasmine in molti modi diversi:
- nel vecchio modo includendo sia il core Jasmine che i file di test usando un tag
<scri
pt>, - come strumento CLI usando Node.js,
- come libreria nel Nodo.js,
- come parte di un sistema di build come Gulp.js o Grunt.js tramite grunt-contrib-jasmine e gulp-jasmine-browser
Puoi anche usare Jasmine per testare il tuo codice Python con jasmine-py che può essere installato da PyPI usando il comando pip install jasmine
. Questo pacchetto contiene sia un server Web che serve ed esegue una suite Jasmine per il progetto e uno script CLI per l’esecuzione di test e integrazioni continue.
Jasmine è disponibile anche per progetti Ruby tramite jasmine-gem che può essere installato aggiungendogem 'jasmine'
al tuo Gemfile ed eseguendobundle install
. Include un server per servire ed eseguire test, uno script CLI e anche generatori per progetti Ruby on Rails.
Ora concentriamoci su come usare Jasmine con JavaScript:
Utilizzando Standalone Jasmine
Inizia scaricando l’ultima versione di Jasmine dalla pagina release.
Quindi estrarre semplicemente il file zip, preferibilmente all’interno di una cartella nel progetto che si desidera testare.
La cartella conterrà un gruppo di file e cartelle predefiniti:
/src
: contiene i file di origine che si desidera testare. Questo può essere eliminato se hai già impostato la cartella del tuo progetto o può essere utilizzato anche quando appropriato per ospitare il tuo codice sorgente.
/lib
: contiene i file principali di Jasmine.
/spec
: contiene i test che stai per scrivere.
SpecRunner.html
: questo file viene utilizzato come test runner. Esegui le tue specifiche semplicemente lanciando questo file.
Questo è il contenuto di un default SpecRunner.html
file:
<!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>
Ricordate che è necessario modificare il file inclusi nel /src
e /spec
cartelle per contenere l’effettiva origine e file di prova.
Utilizzo di Jasmine come libreria
Puoi anche utilizzare Jasmine come libreria nel tuo progetto. Ad esempio, il seguente codice importa ed esegue Jasmine:
var Jasmine = require('jasmine');var jasmine = new Jasmine();jasmine.loadConfigFile('spec/support/jasmine.json');jasmine.execute();
Prima richiediamo/import Jasmine e usiamo il metodo loadConfigFile()
per caricare il file di configurazione disponibile dal percorso spec/support/jasmine.json
quindi infine eseguiamo Jasmine.
Utilizzando Jasmine tramite la CLI
È anche possibile utilizzare Jasmine dalla CLI che consente di eseguire facilmente i test Jasmine e di output predefinito i risultati nel terminale.
Seguiremo questo approccio per eseguire i nostri test di esempio in questa guida, quindi prima vai avanti ed esegui il seguente comando per installare Jasmine a livello globale:
npm install -g jasmine
Potrebbe essere necessario eseguire sudo per installare i pacchetti npm a livello globale a seconda della configurazione npm.
Ora, creare una cartella per il vostro progetto e navigare all’interno di esso:
$ mkdir jasmine-project $ cd jasmine-project
quindi, eseguire il seguente comando per inizializzare il tuo progetto per Jasmine:
Questo comando crea semplicemente una specifica cartella e un file di configurazione JSON. Questo è l’output del dir
comando:
.└── spec └── support └── jasmine.json2 directories, 1 file
Questo è il contenuto di un default jasmine.json
file:
{ "spec_dir": "spec", "spec_files": pec.js" ], "helpers": , "stopSpecOnExpectationFailure": false, "random": true}
-
spec_dir
: specifica la posizione in cui Jasmine cerca i file di test. -
spec_files
: specifica i pattern dei file di test, per impostazione predefinita tutti i file JS che terminano con Spec o spec strings. -
helpers
: specifica dove Jasmine cerca i file di supporto. I file helper vengono eseguiti prima delle specifiche e possono essere utilizzati per definire i matcher personalizzati. -
stopSpecOnExpectationFailure
: quando impostato su true interromperà immediatamente una specifica sul primo errore di un’aspettativa (può essere usato come opzione CLI tramite--stop-on-failure
). -
random
: quando impostato su true Jasmine eseguirà in modo pseudo casuale i casi di test (può essere usato come opzione CLI tramite--random
).
Gli array spec_files
e helpers
possono anche contenere pattern Glob (grazie al pacchetto node-glob) per specificare percorsi di file che sono pattern che di solito si usano per specificare un set di file quando si lavora in Bash (ad esempio ls *.js
).
Se non si utilizza la posizione predefinita per il file di configurazione jasmine.json
, è sufficiente specificare la posizione personalizzata tramite l’opzione jasmine --config
.
Puoi trovare altre opzioni CLI dai documenti ufficiali.
Comprendere Jasmine
In questa sezione impareremo gli elementi di base dei test di Jasmine come suite, specifiche, aspettative, accoppiatori e spie, ecc.
Nella cartella del progetto, eseguire il seguente comando per inizializzare un nuovo Nodo modulo:
Questo creerà un package.json
file con le informazioni di default:
{ "name": "jasmine-project", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": , "author": "", "license": "ISC"}
Avanti, creare un index.js
file e aggiungere il codice riportato di seguito:
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};
Suite
Una suite gruppi di occhiali o di casi di test. Viene utilizzato per testare un comportamento specifico del codice JavaScript che di solito è incapsulato da un oggetto/classe o una funzione. Viene creato utilizzando la funzione Jasmine global describe()
che prende due parametri, il titolo della suite di test e una funzione che implementa il codice effettivo della suite di test.
Iniziamo creando la nostra prima suite di test. All’interno della cartella spec
creare un file MyJSUtilitiesSpec.js
e aggiungere:
describe("MyJSUtilities", function() { /* ... */ });
MyJSUtilities è il nome di questa suite di test di primo livello.
Come raggruppare e Nest Suite
Per una migliore organizzazione e descrivere con precisione la nostra serie di test possiamo nest suite all’interno della suite di primo livello. Per esempio, aggiungiamo due suite al MyJSUtilities suite:
describe("String Utils", function() { /*...*/});describe("Math Utils", function() { /*...*/});
all’Interno della Matematica Utils suite, diamo anche aggiungere due nidificati suite:
describe("Basic Math Utils", function() { /* ... */ }); describe("Advanced Math Utils", function() { /* ... */ });
Siamo raggruppamento delle relative prove in test per la Stringa di Utils, la Matematica di Base Utils e Matematica Avanzata Utils e di nidificazione all’interno del livello superiore suite di test MyJSUtilities. Questo comporrà le tue specifiche come alberi simili a una struttura di cartelle.
La struttura di nidificazione verrà mostrata nel report che semplifica la ricerca di test falliti.
Come escludere le suite
È possibile disattivare temporaneamente una suite utilizzando la funzione xdescribe()
. Ha la stessa firma (parametri) di una funzione describe()
che significa che è possibile disabilitare rapidamente le suite esistenti semplicemente aggiungendo un x
alla funzione.
Le specifiche all’interno di una funzione xdescribe()
verranno contrassegnate in sospeso e non eseguite nel report.
Specifiche
Una specifica dichiara un test case che appartiene a una suite di test. Questo viene fatto chiamando la funzione Jasmine globalit()
che prende due parametri, il titolo della specifica (che descrive la logica che vogliamo testare) e una funzione che implementa il caso di test effettivo.
Una specifica può contenere una o più aspettative. Ogni aspettativa è semplicemente un’asserzione che può restituire true
o false
. Affinché la specifica venga passata, tutte le aspettative appartenenti alla specifica devono essere true
altrimenti la specifica fallisce.
All’interno della nostra suite String Utils, aggiungi queste specifiche:
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() { /*...*/ });});
All’interno della nostra suite Basic Math Utils aggiungiamo alcune specifiche:
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() { /*...*/ }); });
Per le utilità matematiche avanzate, aggiungiamo le specifiche:
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() { /*...*/ }); });
Come escludere le specifiche
Proprio come le suite, puoi anche escludere le singole specifiche usando la funzione xit()
che disabilita temporaneamente le specifiche it()
e contrassegna le specifiche come in sospeso.
Aspettative
Le aspettative vengono create utilizzando la funzioneexpect()
che assume un valore chiamato reale (questo può essere valori, espressioni, variabili, funzioni o oggetti ecc.). Le aspettative compongono le specifiche e vengono utilizzate insieme alle funzioni matcher (tramite concatenamento) per definire ciò che lo sviluppatore si aspetta da una specifica unità di codice da eseguire.
Una funzione matcher confronta tra un valore effettivo (passato alla funzioneexpect()
con cui è concatenato) e un valore atteso (passato direttamente come parametro al matcher) e restituisce true o false che passa o fallisce le specifiche.
È possibile concatenare la funzione expect()
con più matcher. Per negare/invertire il risultato booleano di qualsiasi matcher, è possibile utilizzare la parola chiave not
prima di chiamare il matcher.
Implementiamo le specifiche del nostro esempio. Per ora useremo useremo expect()
con il nothing()
matcher che fa parte dei matcher incorporati che vedremo un po ‘ più tardi. Questo passerà tutte le specifiche dal momento che non ci aspettiamo nulla a questo punto.
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(); }); }); });});
Questo è uno screenshot dei risultati a questo punto:
Abbiamo otto specifiche passate e zero guasti.
È possibile utilizzare i matcher incorporati o anche creare i propri matcher personalizzati per le proprie esigenze specifiche.
Built-In Matcher
Jasmine fornisce un ricco set di built-in matcher. Vediamo alcuni di quelli importanti:
-
toBe()
per la prova di identità, -
toBeNull()
per la verifica dellanull
-
toBeUndefined()/toBeDefined()
per la verifica dellaundefined
/nonundefined
-
toBeNaN()
per il test per la NaN (Not A Number) -
toEqual()
per il test per la parità, -
toBeFalsy()/toBeTruthy()
per il test per la falsità/veridicità etc.
È possibile trovare l’elenco completo dei matcher dai documenti.
Implementiamo ora le nostre specifiche con alcuni di questi abbinamenti quando appropriato. Prima importa le funzioni che stiamo testando nel nostro fileMyJSUtilitiesSpec.js
:
const utils = require("../index.js");
Quindi, inizia con la stringa Utils suite e cambiaexpect().nothing()
con le aspettative appropriate.
Ad esempio per la prima specifica, ci aspettiamo che il metodo toLowerCase()
venga prima definito e in secondo luogo restituisca una stringa minuscola, ad esempio:
it("should be able to lower case a string",function() { expect(utils.toLowerCase).toBeDefined(); expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world"); });
Questo è il codice completo per la 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"); }); });
Custom Matchers
Jasmine offre la possibilità di scrivere custom matchers per implementare asserzioni non coperte dai built-in matchers o solo per rendere i test più descrittivi e leggibili.
Ad esempio, prendiamo le seguenti specifiche:
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(); });
Supponiamo che il metodoisEven()
non sia implementato. Se eseguiamo i test otterremo messaggi come la seguente schermata:
Il messaggio di errore che riceviamo dice Expected undefined da definire che non ci dà alcun indizio di ciò che sta accadendo. Quindi rendiamo questo messaggio più significativo nel contesto del nostro dominio di codice (questo sarà più utile per basi di codice complesse). Per questo motivo, creiamo un matcher personalizzato.
Creiamo matcher personalizzati usando il metodoaddMatchers()
che accetta un oggetto composto da una o più proprietà che verranno aggiunte come matcher. Ogni struttura deve fornire una fabbrica di funzione che prende due parametri: util
, che ha una serie di funzioni di utilità per matcher per l’uso (vedere: matchersUtil.js
) e customEqualityTesters
che deve essere passato se util.equals
si chiama, e deve restituire un oggetto con un compare
funzione che sarà chiamato a verificare l’aspettativa.
È necessario registrare il matcher personalizzato prima di eseguire ogni specifica utilizzando il metodobeforeEach()
:
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;}}}});});/*...*/});
E ‘ possibile, quindi, utilizzare il matcher personalizzato invece di expect(utils.isEven).toBeDefined()
:
expect().hasEvenMethod();
Questo ci darà un migliore messaggio di errore:
Utilizzando beforeEach() e afterEach()
Per l’inizializzazione e la pulizia di occhiali, Gelsomino fornisce due funzioni globali, beforeEach()
e afterEach()
:
-
beforeEach
funzione viene chiamata una volta prima di ogni spec in la suite in cui è chiamato. - La funzione
afterEach
viene chiamata una volta dopo ogni specifica nella suite in cui viene chiamata.
Ad esempio, se è necessario utilizzare qualsiasi variabile nella suite di test, è sufficiente dichiararle all’inizio della funzione describe()
e inserire qualsiasi codice di inizializzazione o istanza all’interno di una funzione beforeEach()
. Infine, è possibile utilizzare la funzione afterEach()
per reimpostare le variabili dopo ogni specifica in modo da poter eseguire test di unità puri senza la necessità di ripetere l’inizializzazione e il codice di pulizia per ogni specifica.
La funzionebeforeEach()
è anche perfettamente combinata con molte API Jasmine come iladdMatchers()
metodo per creare abbinamenti personalizzati o anche con ladone()
funzione per attendere le operazioni asincrone prima di continuare il test.
Errore di un test
È possibile forzare un test a fallire utilizzando il metodo globalefail()
disponibile in Jasmine. Ad esempio:
it("should explicitly fail", function () { fail('Forced to fail'); });
Si dovrebbe ottenere il seguente errore:
Test per le eccezioni
Quando si sta testando il codice, gli errori e le eccezioni potrebbero essere generati, quindi potrebbe essere necessario testare questi scenari. Jasmine fornisce itoThrow()
etoThrowError()
per verificare quando viene generata un’eccezione o per verificare una specifica eccezione, rispettivamente.
Ad esempio se abbiamo una funzione che genera un’eccezioneTypeError
:
function throwsError() { throw new TypeError("A type error"); }
Si potrebbe scrivere una spec che prova per se viene generata un’eccezione:
it('it should throw an exception', function () { expect(throwsError).toThrow(); });
O si potrebbe anche usare il test per la specifica TypeError
eccezione:
it('it should throw a TypeError', function () { expect(throwsError).toThrowError(TypeError); });
la Comprensione Spies
il Più delle volte, i metodi dipendono da altri metodi. Ciò significa che quando si sta testando un metodo, si può anche finire per testare le sue dipendenze. Questo non è raccomandato nei test, cioè è necessario assicurarsi di testare la funzione pura isolando il metodo e vedendo come si comporta dato un insieme di input.
Jasmine fornisce spie che possono essere utilizzate per spiare / ascoltare le chiamate al metodo sugli oggetti e segnalare se viene chiamato un metodo e con quale contesto e argomenti.
Jasmine fornisce due modi per spiare le chiamate di metodo: utilizzando i metodispyOn()
ocreateSpy()
.
È possibile utilizzare spyOn()
quando il metodo esiste già sull’oggetto, altrimenti è necessario utilizzare jasmine.createSpy()
che restituisce una nuova funzione.
Per impostazione predefinita una spia segnalerà solo se una chiamata è stata eseguita senza chiamare tramite la funzione spiata (i.e la funzione di interrompere l’esecuzione), ma è possibile modificare il comportamento predefinito utilizzando questi metodi:
-
and.callThrough()
: chiamata mediante la funzione originale, -
and.returnValue(value)
: tornare al valore specificato, -
and.callFake(fn)
: chiamare il falso invece la funzione originale, -
and.throwError(err)
: genera un errore, -
and.stub()
: ripristina l’impostazione predefinita stubbing comportamento.
È possibile utilizzare una spia per raccogliere statistiche di runtime sulla funzione spiata, ad esempio se si desidera sapere quante volte la funzione è stata chiamata.
Diciamo che vogliamo assicurarci che il nostro metodotoUpperCase()
stia facendo uso del metodoString.toUpperCase()
incorporato, dobbiamo semplicemente spiare String.toUpperCase()
usando:
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); });
Il test è fallito a causa per la seconda aspettativa perché utils.toUpperCase("hello world")
restituito indefinito, invece del previsto HELLO WORLD. Questo perché, come abbiamo detto, prima dopo aver creato la spia sutoUpperCase()
, il metodo non viene eseguito. Dobbiamo cambiare questo comportamento predefinito chiamando callThrough()
:
Si noti che una funzione
spy
sostituisce la funzione spiata con uno stub per impostazione predefinita. Se invece è necessario chiamare la funzione originale, è possibile aggiungere.and.callThrough()
all’oggettospy
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callThrough();
Ora tutte le aspettative passano.
Puoi anche usare and.callFake()
o and.returnValue()
per falsificare la funzione spiata o solo il valore di ritorno se non chiami attraverso la funzione effettiva:
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.returnValue("HELLO WORLD");
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callFake(function(){ return "HELLO WORLD"; });
Ora, se noi alla fine non utilizzando il costruito nel String.toUpperCase()
nel nostro utils.toUpperCase()
attuazione, otterremo questi errori:
La due le aspettative expect(String.prototype.toUpperCase).toHaveBeenCalled()
expect(spytoUpperCase.calls.count()).toEqual(1)
non sono riuscita.
Come gestire l’asincronia in Jasmine
Se il codice che si sta testando contiene operazioni asincrone, è necessario un modo per far sapere a Jasmine quando le operazioni asincrone sono state completate.
Per impostazione predefinita, Jasmine attende che qualsiasi operazione asincrona, definita da una callback, una promessa o la parola chiaveasync
, sia terminata. Se Gelsomino trova un callback, promessa o async parola chiave in una di queste funzioni: beforeEach
afterEach
beforeAll
afterAll
e it
si di attesa per il asincrona essere fatto prima di procedere alla successiva operazione.
Usando done () con beforeEach () / it ()..
Prendiamo il nostro esempiosimulateAsyncOp()
che simula un’operazione asincrona usandosetTimeout()
. In uno scenario reale questa può essere una richiesta Ajax o qualsiasi cosa simile che accade in modo asincrono:
function simulateAsyncOp(callback){
setTimeout(function () { callback(); }, 2000); }
Per testare questa funzione possiamo usare la funzione beforeEach()
con lo speciale done()
richiamata. Il nostro codice deve richiamare done()
per dire a Jasmine che l’operazione asincrona è stata completata:
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);});});
Possiamo notare rapidamente un inconveniente di questo metodo, quindi abbiamo bisogno di scrivere il nostro codice per accettare ildone()
callback. Nel nostro caso, non abbiamo hardcode il metododone()
nel nostrosimulateAsyncOp(fn)
ma abbiamo fornito un parametro di callback solo per essere in grado di chiamaredone()
.
Utilizzo delle promesse
Se non si desidera creare codice che dipende da come si scrive il test, è possibile utilizzare una promessa e chiamare ildone()
callback quando la promessa è stata risolta. O meglio ancora, in Jasmine 2.7+, se il tuo codice restituisce un Promise
, Jasmine aspetterà fino a quando non verrà risolto o rifiutato prima di eseguire il codice successivo.
Utilizzando async/await
Jasmine 2.7+ supportaasync
eawait
chiamate in specifiche. Questo ti allevia dal mettere asserzioni in un blocco.then()
o.catch()
.
it("should work with async/await", async () => { let completed = false; completed = await utils.simulateAsyncOp(); expect(completed).toEqual(true); });
Questa è l’implementazione di simulateAsyncOp
:
function simulateAsyncOp() {
return new Promise(resolve => { setTimeout(() => { resolve(true); }, 1000); }); }
Utilizzo di Jasmine Clock
L’orologio Jasmine viene utilizzato per testare il codice asincrono che dipende da funzioni temporali come setTimeout()
allo stesso modo testiamo il codice sincrono prendendo in giro le API basate sul tempo con metodi personalizzati. In questo modo, è possibile eseguire le funzioni testate in modo sincrono controllando o avanzando manualmente l’orologio.
È possibile installare l’orologio Jasmine chiamando la funzione jasmine.clock().install
nella specifica o nella suite.
Dopo aver utilizzato l’orologio, è necessario disinstallarlo per ripristinare le funzioni originali.
Con Jasmine clock, è possibile controllare le funzioni JavaScript setTimeout
o setInterval
spuntando l’orologio per avanzare nel tempo utilizzando la funzione jasmine.clock().tick
, che prende il numero di millisecondi con cui è possibile spostarsi.
Puoi anche usare l’orologio Jasmine per deridere la data corrente.
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);});
Questa è la funzione simulateAsyncOp
:
function simulateAsyncOp(callback){
setTimeout(function () { callback(); }, 1000); }
Nel caso in cui non sia stata specificata un’ora per la funzione
mockDate
, verrà utilizzata la data corrente.
Gestione degli errori
Se il tuo codice asincrono fallisce a causa di qualche errore, vuoi che le tue specifiche falliscano correttamente. A partire da Jasmine 2.6 + eventuali errori non gestiti vengono inviati alle specifiche attualmente eseguite.
Jasmine fornisce anche un modo che puoi usare se hai bisogno di fallire esplicitamente le tue specifiche:
- con il
done()
callback conbeforeEach()
chiamando ildone.fail(err)
metodo - semplicemente passando un errore
done(err)
callback Jasmine (3+), - chiama
reject()
metodo di unPromise
.
Conclusione
In questa guida abbiamo introdotto Jasmine e visto come iniziare a utilizzare Jasmine per testare il codice JavaScript. Grazie per la lettura!
Questo articolo è stato originariamente pubblicato in techiediaries.