Sappiamo tutti che dovremmo testare il nostro codice, ma in realtà non lo facciamo. Immagino sia giusto dire che la maggior parte di noi lo rimprovera perché, nove volte su dieci, significa imparare un altro concetto. In questo tutorial, ti presenterò un ottimo framework per testare il tuo codice JavaScript con facilità.
A proposito, sapevi che puoi correggere i tuoi errori JavaScript velocemente e facilmente da un esperto di Envato Studio?
ThemeManiac, ad esempio, risolverà errori JavaScript o problemi di compatibilità del browser sul proprio sito Web o applicazione Web. Le correzioni possono essere completate molto velocemente, in base alla complessità e alle informazioni disponibili. Può anche riorganizzare i tuoi script e creare un'esperienza utente completamente nuova. Ha completato più di 1.000 posti di lavoro su Envato Studio, con il 99% dei clienti che lo consigliano.
Oggi impareremo a conoscere il framework di test BDS per Jasmine. Ma ci fermiamo qui per una prima deviazione, per parlare molto brevemente di BDD e TDD. Se non hai familiarità con questi acronimi, rappresentano Sviluppo guidato dal comportamento e Sviluppo guidato dai test. Sono nel bel mezzo dell'apprendimento su ciò che ciascuno di questi è in pratica e su come sono diversi, ma ecco alcune delle differenze fondamentali:
BDD e TDD? stare per Sviluppo guidato dal comportamento e Sviluppo guidato dai test.
TDD nella sua forma più semplice è proprio questo:
È abbastanza facile da capire, eh?
Il BDD è un po 'più complesso: come ho capito ora, non penso che tu o io come singolo sviluppatore possiamo effettivamente esercitarlo pienamente; è più una questione di squadra. Ecco alcune delle pratiche di BDD:
Per saperne di più, puoi leggere l'ampio articolo di Wikipedia (da cui sono stati presi quei punti).
Tutto questo per dire che, mentre Jasmine si autofinanzia come un framework BDD, lo useremo in un modo più TDD. Ciò non significa che lo stiamo usando male, però. Una volta che abbiamo finito, sarai in grado di testare il tuo JavaScript con facilità? e mi aspetto che tu lo faccia!
Jasmine prende molti spunti da Rspec.
Se hai familiarità con Rspec, il di fatto Quadro BDD, vedrai che Jasmine prende molti spunti da Rspec. I test al gelsomino sono principalmente due parti: descrivere
blocchi e esso
blocchi. Vediamo come funziona.
Vedremo alcuni test più da vicino in pochi, ma per ora, lo terremo semplice:
descrivere ('JavaScript addition operator', function () it ('aggiunge due numeri insieme', function () expect (1 + 2) .toEqual (3);););
Sia il descrivere
e esso
le funzioni prendono due parametri: una stringa di testo e una funzione. La maggior parte dei framework di test cerca di leggere il più possibile l'inglese, e puoi vederlo con Jasmine. Innanzitutto, nota che la stringa è passata a descrivere
e la stringa passata a esso
forma una frase (di sorta):? L'operatore di aggiunta di JavaScript aggiunge due numeri insieme? Quindi, continuiamo a mostrare come.
Dentro quello esso
blocco, è possibile scrivere tutto il codice di installazione necessario per il test. Non ne abbiamo bisogno per questo semplice esempio. Una volta che sei pronto per scrivere il codice di prova effettivo, inizierai con aspettarsi
funzione, passandola qualunque cosa tu stia testando. Notate come questo forma anche una frase: ci aspettiamo che 1 + 2 sia uguale a 3.?
Ma sto andando oltre. Come ho detto, qualunque valore tu passi aspettarsi
sarà testato Il metodo che chiami, fuori dal valore restituito aspettarsi
, sarà determinato da quale test verrà eseguito. Questo gruppo di metodi è chiamato 'matcher', e ne esamineremo alcuni oggi. In questo caso, stiamo usando il toEqual
matcher, che controlla per vedere se il valore è passato a aspettarsi
e il valore è passato a toEqual
sono lo stesso valore.
Penso che tu sia pronto per portarlo al livello successivo, quindi impostiamo un semplice progetto usando Jasmine.
Il gelsomino può essere usato da solo; oppure puoi integrarlo con un progetto Rails. Faremo il primo. Mentre Jasmine può funzionare fuori dal browser (pensa Nodo, tra gli altri posti), possiamo ottenere un piccolo template davvero bello con il download.
Quindi, vai alla pagina di download indipendente e ottieni l'ultima versione. Dovresti ottenere qualcosa del genere:
Troverai i file del framework Jasmine nel file lib
cartella. Se preferisci strutturare i tuoi progetti in modo diverso, ti preghiamo di farlo; ma lo terremo per ora.
C'è in realtà qualche codice di esempio cablato in questo modello di progetto. L'attuale? JavaScript (il codice che vogliamo testare) può essere trovato nel src
sottodirectory; metteremo i nostri a breve. Il codice di prova: il Specifiche-andare nel spec
cartella. Non preoccuparti per il SpecHelper.js
file appena ancora; torneremo a quello.
Quello SpecRunner.html
il file è ciò che esegue i test in un browser. Aprilo (e controlla la casella di controllo "passata" nell'angolo in alto a destra) e dovresti vedere qualcosa di simile a questo:
Questo ci mostra che tutti i test per il progetto di esempio stanno passando. Una volta completato questo tutorial, ti consiglio di aprire il spec / PlayerSpec.js
file e sfoglia quel codice. Ma in questo momento, proviamo questo test di scrittura.
convert.js
nel src
cartella.convertSpec.js
nel spec
cartella,SpecRunner.html
file e rinominarlo SpecRunner.original.html
.Rimuovere i collegamenti ai file di progetto di esempio in SpecRunner.html
e aggiungi queste righe:
Ora siamo pronti per creare una mini-libreria che convertirà tra unità di misura. Inizieremo scrivendo i test per la nostra mini-biblioteca.
Quindi, scriviamo i nostri test, dobbiamo farlo?
define ("Converti libreria", function () describe ("convertitore di distanza", function () ); describe ("volume converter", function () ););
Iniziamo da questo; stiamo testando il nostro Convertire
biblioteca. Noterai che stiamo nidificando descrivere
dichiarazioni qui. Questo è perfettamente legale. In realtà è un ottimo modo per testare frammenti di funzionalità separati della stessa base di codice. Invece di due separati descrivere
chiede Convertire
conversioni a distanza e conversioni di volume della biblioteca, possiamo avere una suite di test più descrittiva come questa.
Ora, sui test reali. Ripeterò l'interno descrivere
chiama qui per la vostra convenienza.
descrivere ("convertitore di distanza", function () it ("converte pollici in centimetri", function () expect (Convert (12, "in"). a ("cm")). toEqual (30.48);) ; ("converte i centimetri in metri", function () expect (Convert (2000, "cm"). a ("yards")). a Equal (21,87);););
Ecco i nostri test per le conversioni a distanza. È importante notare qualcosa qui: non abbiamo scritto un granello di codice per il nostro Convertire
libreria ancora, quindi in questi test stiamo facendo molto più che controllare per vedere se funziona: in realtà stiamo decidendo come verrà usato (e quindi implementato). Ecco come abbiamo deciso di fare le nostre conversioni:
Convertire(, ).a( );
Sì, sto prendendo spunto dal modo in cui Jasmine ha implementato i suoi test, ma penso che sia un bel formato. Quindi, in questi due test, ho effettuato personalmente le conversioni (ok, con una calcolatrice) per vedere quali dovrebbero essere i risultati delle nostre chiamate. Stiamo usando il toEqual
matcher per vedere se i nostri test passano.
Ecco i test del volume:
descrivere ("volume converter", function () it ("converte litri in galloni", function () expect (Convert (3, "litri"). a ("gallons")). toEqual (0,79);) ; ("converte galloni in tazze", function () expect (Converti (2, "gallons"). in ("cups")). in Equal (32);););
E aggiungerò altri due test nel nostro livello superiore descrivere
chiamata:
("genera un errore quando passa una sconosciuta dall'unità", function () var testFn = function () Convert (1, "dollar"). a ("yens"); expect (testFn) .toThrow ( nuovo errore ("non riconosciuto dall'unità"));); ("getta un errore quando viene passato a un'unità sconosciuta", function () var testFn = function () Convert (1, "cm"). a ("furlongs"); expect (testFn) .toThrow ( nuovo errore ("non riconosciuto to-unit")););
Questi controllano gli errori che dovrebbero essere lanciati quando unità sconosciute vengono passate nel Convertire
funzione o il a
metodo. Noterai che sto completando la conversione effettiva in una funzione e passando a quella aspettarsi
funzione. Questo perché non possiamo chiamare la funzione come aspettarsi
parametro; abbiamo bisogno di consegnare una funzione e lasciare che chiami la funzione stessa. Dal momento che abbiamo bisogno di passare un parametro a quello a
funzione, possiamo farlo in questo modo.
L'altra cosa da notare è che sto introducendo un nuovo matcher: gettare
, che accetta un oggetto errore. Vedremo presto altri corrieri.
Ora, se apri SpecRunner.html
in un browser, otterrai questo:
Grande! I nostri test stanno fallendo. Ora, apriamo il nostro convert.js
file e fare un po 'di lavoro:
funzione Converti (numero, daUnità) var conversioni = distanza: metri: 1, cm: 0.01, piedi: 0.3048, pollici: 0.0254, iarde: 0.9144, volume: litri: 1, galloni: 3.785411784, tazze: 0.236588236 , betweenUnit = false, type, unit; for (digita conversioni) if (conversions (type)) if ((unit = conversions [type] [fromUnit])) betweenUnit = number * unit * 1000; return to: function (toUnit) if (betweenUnit) for (type in conversions) if (conversions.hasOwnProperty (type)) if ((unit = conversions [type] [toUnit])) return fix (betweenUnit / (unit * 1000)); lancia un nuovo errore ("non riconosciuto all'unità"); else throw new Error ("non riconosciuto dall'unità"); function fix (num) return parseFloat (num.toFixed (2)); ;
Non discuteremo di questo, perché stiamo imparando Jasmine qui. Ma qui ci sono i punti principali:
iarde: 0,9144
, sai che è quanti metri ci sono in un metro. Quindi, per convertire i cantieri, ad esempio, in centimetri, ci moltiplichiamo cantieri
dal primo parametro (per ottenere il numero di metri) e quindi dividere il prodotto per centimetro
, il numero di metri in un centimetro. In questo modo, non dobbiamo memorizzare i tassi di conversione per ogni coppia di valori. Ciò facilita anche l'aggiunta di nuovi valori in seguito.fromUnit
alla chiave giusta.Convertire
funzione, memorizziamo il valore intermedio in betweenUnit
, che è inizializzato a falso
. In questo modo, se non abbiamo il fromUnit
, betweenUnit
sarà falso
entrare nel a
metodo, quindi viene generato un errore.toUnit
, verrà generato un errore diverso. Altrimenti, divideremo come necessario e restituire il valore convertito.Ora, torna a SpecRunner.html
e ricaricare la pagina. Ora dovresti vedere questo (dopo aver controllato? Show passed?):
Ecco qua! I nostri test stanno passando. Se stessimo sviluppando un vero progetto qui, scriveremmo test per una certa porzione di funzionalità, li faremo passare, scrivere test per un altro controllo, renderli pass, ecc. Ma poiché questo era un semplice esempio, lo abbiamo appena fatto tutto in un colpo solo.
E ora che hai visto questo semplice esempio di utilizzo di Jasmine, diamo un'occhiata ad alcune altre funzionalità che ti offre.
Finora, abbiamo usato due giocatori: toEqual
e gettare
. Ci sono, naturalmente, molti altri. Ecco alcuni che probabilmente troverai utili; puoi vedere l'intera lista sul wiki.
Se vuoi solo assicurarti che una variabile o una proprietà sia definita, c'è un corrispondente per quello. C'è anche uno per confermare che una variabile o proprietà è non definito
.
("è definito", function () var name = "Andrew"; expect (name) .toBeDefined ();) it ("non è definito", function () var name; expect (name) .toBeUndefined (););
Se qualcosa dovrebbe essere vero o falso, questi matchers lo faranno.
("è vero", function () expect (Lib.isAWeekDay ()). toBeTruthy ();); ("è falso", function () expect (Lib.finishedQuiz) .toBeFalsy (););
Per tutti voi persone numero. Sai come funzionano questi:
("è minore di 10", function () expect (5) .toBeLessThan (10);); ("è maggiore di 10", function () expect (20) .toBeGreaterThan (10););
Hai un testo di output che dovrebbe corrispondere a un'espressione regolare? Il toMatch
il matcher è pronto e disponibile.
("restituisce il testo corretto", function () expect (cart.total ()). toMatch (/ \ $ \ d *. \ d \ d /););
Questo è abbastanza utile. Controlla se un array o una stringa contiene un elemento o una sottostringa.
("dovrebbe contenere arance", function () expect (["apples", "arance", "pears"]). toContain ("arance"););
Ci sono anche altri giocatori che puoi trovare nella wiki. Ma cosa succede se vuoi un matcher che non esiste? In realtà, dovresti essere in grado di fare qualsiasi cosa con qualche codice di impostazione e gli abbinamenti di Jasmine, ma a volte è meglio astrarre parte di quella logica per avere un test più leggibile. Serendipitosamente (beh, in realtà no), Jasmine ci consente di creare i nostri matchers. Ma per fare questo, prima dovremo imparare qualcos'altro.
Spesso, quando si verifica una base di codice, si desidera eseguire alcune righe di codice di impostazione per ogni test di una serie. Sarebbe doloroso e prolisso copiarlo per tutti esso
chiama, quindi Jasmine ha una piccola funzionalità utile che ci consente di designare il codice da eseguire prima o dopo ogni test. Vediamo come funziona:
define ("MyObject", function () var obj = new MyObject (); beforeEach (function () obj.setState ("clean");); it ("cambia stato", function () obj.setState ("dirty"); expect (obj.getState ()). toEqual ("dirty");) it ("aggiunge stati", function () obj.addState ("packaged"); expect (obj.getState ( )). toEqual (["clean", "packaged"]);));
In questo esempio forzato, puoi vedere come, prima dell'esecuzione di ogni test, lo stato di obj
è impostato su? clean ?. Se non lo facessimo, la modifica apportata a un oggetto in un test precedente verrà mantenuta per il test successivo per impostazione predefinita. Naturalmente, potremmo anche fare qualcosa di simile con il Dopo ogni
funzione:
define ("MyObject", function () var obj = new MyObject ("clean"); // imposta lo stato iniziale afterEach (function () obj.setState ("clean");); it ("cambia stato") , function () obj.setState ("dirty"); expect (obj.getState ()). toEqual ("dirty");) it ("aggiunge stati", function () obj.addState ("impacchettato") ); expect (obj.getState ()). toEqual (["clean", "packaged"]);));
Qui, stiamo impostando l'oggetto per cominciare, e quindi averlo corretto dopo ogni test. Se vuoi il MyObject
funziona in modo che tu possa provare questo codice, puoi farlo qui in un GistHub.
Come abbiamo detto prima, gli abbinamenti con i clienti sarebbero probabilmente utili a volte. Quindi scriviamone uno. Possiamo aggiungere un matcher in uno a beforeeach
chiama o un esso
chiama (beh, immagino che tu poteva fallo in un Dopo ogni
chiama, ma non avrebbe molto senso). Ecco come si avvia:
beforeEach (function () this.addMatchers (););
Piuttosto semplice, eh? Noi chiamiamo this.addMatchers
, passandogli un parametro oggetto. Ogni chiave in questo oggetto diventerà il nome di un corrispondente e la funzione associata (il valore) sarà come viene eseguita. Diciamo che vogliamo creare un matcher che controlli per vedere se un numero è tra altri due. Ecco cosa scriveresti:
beforeEach (function () this.addMatchers (toBeBetween: function (rangeFloor, rangeCeiling) if (rangeFloor> rangeCeiling) var temp = rangeFloor; rangeFloor = rangeCeiling; rangeCeiling = temp; return this.actual> rangeFloor && this. effettivo < rangeCeiling; ); );
Prendiamo semplicemente due parametri, assicurandoci che il primo sia più piccolo del secondo, e restituiamo un'istruzione booleana che si considera vera se le nostre condizioni sono soddisfatte. La cosa importante da notare qui è come otteniamo il valore che è stato passato al aspettarsi
funzione: this.actual
.
("è tra 5 e 30", function () expect (10) .toBeBetween (5, 30);); ("è tra 30 e 500", function () expect (100) .toBeBetween (500, 30););
Questo è ciò che SpecHelper.js
il file fa; ha un beforeeach
chiamata che aggiunge il matcher tobePlaying ()
. Controlla!
C'è molto di più che puoi fare con Jasmine: abbinamenti di funzioni, spie, specifiche asincrone e altro. Ti consiglio di esplorare il wiki se sei interessato. Ci sono anche alcune librerie di accompagnamento che semplificano i test nel DOM: Jasmine-jQuery e Jasmine-fixture (che dipende da Jasmine-jQuery).
Quindi, se non stai testando il tuo JavaScript finora, ora è un ottimo momento per iniziare. Come abbiamo visto, la sintassi veloce e semplice di Jasmine rende il test piuttosto semplice. Non c'è ragione per non farlo, ora, c'è?
Se vuoi migliorare ulteriormente lo sviluppo di JavaScript, perché non controllare la gamma di elementi JavaScript su Envato Market? Ci sono migliaia di script, app e snippet di codice per aiutarti.