Non dimenticare di coprire il tuo lato client!

Assicurandoti che la tua applicazione sia testata, puoi ridurre la quantità di bug che trovi nel tuo codice, aumentare la manutenibilità della tua applicazione e progettare un codice ben strutturato. 

I test dell'unità lato client presentano sfide diverse rispetto ai test lato server. Quando si ha a che fare con il codice lato client, ci si troverà a dover lottare per separare la logica dell'applicazione dalla logica DOM, oltre a strutturare il codice JavaScript in generale. Fortunatamente ci sono molte ottime librerie di test lato client per testare il codice, creare metriche sulla copertura del test e analizzare la complessità di questo.


Perché testare a tutti?

Prima di tutto, i test unitari in generale sono un modo per ridurre i bug garantendo che l'applicazione funzioni come dovrebbe. Oltre a ciò, ci sono le nozioni di Test Driven Development (TDD) e Behavior Driven Development (BDD).

Queste due strategie di test delle unità ti aiuteranno a progettare la tua applicazione scrivendo dei test prima scrivi la tua logica di applicazione. Scrivendo i test prima di scrivere il codice, ti stai dando l'opportunità di pensare attraverso il design della tua applicazione.

Ciò accade perché durante la scrittura di test, in pratica stai provando a progettare l'API per il modo in cui interagisci con il tuo codice, in modo da ottenere quindi una visione migliore del suo design. Prima i test ti mostreranno rapidamente tutti i difetti che hai nel tuo progetto perché stai scrivendo un codice di prova che essenzialmente usa il codice che stai scrivendo!

TDD è un processo di scoperta del codice

Scoprirai che TDD ti aiuta a scoprire il tuo codice mentre lo stai scrivendo. Il TDD è riassunto molto rapidamente come "Red, Green, Refactor". Questo significa che scrivi un test, scrivi abbastanza codice per fare il test fallire primo. Poi, scrivi il codice che fa passare il test. Dopo ciò, pensate a ciò che avete appena scritto e rifattorizzato. Bello e facile.

BDD è una presa leggermente diversa su TDD e si basa più su requisiti e specifiche aziendali.


Test lato client

Ci sono molte ragioni per cui dovresti provare il tuo codice lato client. Come accennato prima, aiuterà a ridurre i bug e ti aiuterà a progettare la tua applicazione. Anche il test lato client è importante perché ti offre la possibilità di testare il tuo front end, da solo, lontano dalla tua presentazione. In altre parole, uno dei suoi vantaggi è che si arriva a testare il codice JavaScript senza effettivamente girare su un server delle applicazioni. Basta eseguire i test e assicurarsi che le cose funzionino senza fare clic e testare le cose. In molti casi, non è nemmeno necessario disporre dell'accesso a Internet, a condizione che i test siano impostati correttamente.

Con JavaScript che assume un ruolo così importante nello sviluppo web moderno, è importante imparare come testare il codice e ridurre le possibilità che i bug si introducano nel codice di produzione. Al tuo capo non piace quando succede e nemmeno tu dovresti! In effetti, un buon punto di partenza per lavorare con i test sul lato client è scrivere dei test su una segnalazione di bug. Questo ti consentirà di fare pratica con i test di scrittura quando non hai un posto dove iniziare da zero.

Un altro motivo per testare il tuo codice client è che una volta che una serie di test esiste e ha una copertura decente sul tuo codice, quando sei pronto ad andare e aggiungi nuove funzionalità al tuo codice, sarai in grado di aggiungere la nuova funzione, - Esegui i tuoi test e assicurati di non regredire e interrompere alcuna funzionalità esistente.


Iniziare

Iniziare con i test lato client può essere scoraggiante se non l'hai mai fatto prima. Una delle parti più difficili del testing lato client è capire il modo migliore per isolare il DOM dalla logica dell'applicazione. Questo spesso significa che avrai bisogno di una sorta di astrazione sul DOM. Il modo più semplice per ottenere ciò è attraverso un framework lato client come Knockout.js, Backbone.js o Angular.js, per citarne solo alcuni.

Quando si utilizza una libreria come questa, si arriva a pensare meno a come la pagina viene visualizzata nel browser e più sulle funzionalità della propria applicazione. Non è come se fosse impossibile eseguire un test unitario con un semplice codice JavaScript. In tal caso, la tua vita sarà molto più semplice se disegni il codice in modo tale che il DOM possa essere facilmente estratto.

Scegli una libreria di prova

Ci sono molte diverse librerie di test tra cui scegliere, anche se i tre front runner tendono ad essere QUnit, Moka e Jasmine.

Jasmine e Mocha provengono entrambi dalla scuola BDD di test unitari, mentre QUnit è solo un framework di testing unitario.

Per il resto di questo post, esploreremo usando QUnit come la sua barriera all'ingresso nel testing lato client è molto bassa. Dai un'occhiata a questa introduzione dettagliata a QUnit per ulteriori informazioni.

TDD Il tuo codice con QUnit

Iniziare con QUnit è estremamente semplice. Il seguente codice HTML è tutto ciò di cui hai bisogno:

    Esempio di QUnit    

Per i prossimi esempi, supponiamo che stiamo costruendo un piccolo widget che inserisci un codice di avviamento postale in una casella di testo e restituisce i valori corrispondenti di città, stato e contea usando Geonames. All'inizio mostrerà solo un codice postale, ma non appena il codice di avviamento postale avrà cinque caratteri, recupererà i dati da Geonames. Se è in grado di trovare i dati, mostrerà alcuni altri campi contenenti le informazioni sulla città, sullo stato e sulla contea risultanti. Useremo anche Knockout.js. Il primo passo è scrivere un test negativo.

Pensando un po 'alla progettazione prima che venga scritto il primo test, probabilmente ci devono essere almeno due viewModels, quindi sarà un buon punto di partenza. Per iniziare, definiremo un modulo QUnit e il nostro primo test:

modulo ("retriever del codice postale"); test ("i modelli di visualizzazione dovrebbero esistere", function () ok (FormViewModel, "Dovrebbe esistere un viewModel per il nostro modulo"); ok (AddressViewModel, "Dovrebbe esistere un viewModel per il nostro indirizzo"););

Se esegui questo test, fallirà, ora puoi andare a scrivere il codice per farlo passare:


var AddressViewModel = function (options) ; var FormViewModel = function () this.address = new AddressViewModel (); ;

Questa volta vedrai il verde piuttosto che il rosso. Test come questo sembrano un po 'sciocchi all'inizio, ma sono utili in quanto ti costringono a pensare almeno attraverso alcune delle prime fasi del tuo design.

Il prossimo test che scriveremo funzionerà su AddressViewModelLa funzionalità. Sappiamo dalle specifiche di questo widget che gli altri campi devono essere nascosti all'inizio, fino a quando non vengono trovati i dati per il codice postale.

modulo ("modello vista indirizzo"); test ("dovrebbe mostrare i dati dello stato della città se viene trovato un codice postale", function () var address = new AddressViewModel (); ok (! address.isLocated ()); address.zip (12345); address.city (" pippo "); address.state (" bar "); address.county (" bam "); ok (address.isLocated ()););

Nessuno del codice per questo è stato ancora scritto, ma l'idea qui è che il si trova sarà un osservabile calcolato, che ritorna vero solo quando zip, città, stato e contea sono tutti veri. Quindi, questo test ovviamente fallirà all'inizio, ora scriviamo il codice per farlo passare.

var AddressViewModel = function (options) options = options || ; this.zip = ko.observable (options.zip); this.city = ko.observable (options.city); this.state = ko.observable (options.state); this.county = ko.observable (options.county); this.isLocated = ko.computed (function () return this.city () && this.state () && this.county () && this.zip ();, this); this.initialize (); ;

Ora se esegui nuovamente i test, vedrai il verde!

Questo è, per la sua base, come utilizzare TDD per scrivere test di front end. Idealmente, dopo ogni test fallito, dovresti scrivere il codice più semplice che farà passare il test e poi tornare indietro e rifattorizzare il codice. Puoi imparare molto di più sulle pratiche di TDD, quindi ti suggerisco di leggerlo e studiarlo ulteriormente, ma gli esempi precedenti sono sufficienti per farti pensare prima di scrivere i test.

Dipendenze derisorie con Sinon.js

Sinon.js è una libreria JavaScript che offre la possibilità di spiare, stubare e simulare oggetti JavaScript. Quando scrivi dei test unitari, vuoi assicurarti di essere in grado di testare solo una determinata "unità" di codice. Questo spesso significa che dovrai eseguire una sorta di derisione o di soppressione delle dipendenze per isolare il codice sottoposto a test.

Sinon ha un'API estremamente semplice per farlo. L'API Geonames supporta il recupero dei dati tramite un endpoint JSONP, il che significa che saremo in grado di utilizzare facilmente $ .ajax.

Idealmente, nei test non dovrai dipendere dall'API di Geonames. Potrebbero essere temporaneamente inattivi, la tua connessione internet potrebbe morire, ed è anche più lento effettuare la chiamata ajax. Sinon in soccorso.

test ("dovrebbe cercare di ottenere dati solo se ci sono 5 caratteri", function () var address = new AddressViewModel (); sinon.stub (jQuery, "ajax"). returns (done: $ .noop); .zip (1234); ok (! jQuery.ajax.calledOnce); address.zip (12345); ok (jQuery.ajax.calledOnce); jQuery.ajax.restore (););

Qui in questo test, stiamo facendo alcune cose. Prima di tutto, il sinon.stub la funzione sta effettivamente andando al proxy jQuery.ajax e aggiungi la possibilità di vedere quante volte è stato chiamato e molte altre asserzioni. Come si legge nel test, "dovrebbe solo cercare di ottenere dati se ci sono 5 caratteri", assumeremo che quando l'indirizzo è impostato su"1234", che nessuna chiamata ajax è stata ancora effettuata, quindi impostarla su"12345"e a quel punto dovrebbe essere fatta una chiamata ajax.

Abbiamo quindi bisogno di ripristinare jQuery.ajax al suo stato originale, perché siamo buoni cittadini dei test unitari e vogliamo mantenere i nostri test atomici. Mantenere i test atomici è importante per garantire che un test non dipenda da un altro test e che non vi sia uno stato condiviso tra i test. Possono quindi essere eseguiti in qualsiasi ordine.

Ora che il test è scritto, possiamo eseguirlo, guardarlo fallire e poi scrivere il codice che esegue la richiesta Ajax su Geonames.

AddressViewModel.prototype.initialize = function () this.zip.subscribe (this.zipChanged, this); ; AddressViewModel.prototype.zipChanged = function (value) if (value.toString (). Length === 5) this.fetch (valore); ; AddressViewModel.prototype.fetch = function (zip) var baseUrl = "http://www.geonames.org/postalCodeLookupJSON" $ .ajax (url: baseUrl, dati: "codice postale": zip, "paese": " us ", digitare:" GET ", dataType:" JSONP "). done (this.fetched.bind (this)); ;

Qui ci iscriviamo alle modifiche del codice postale. Ogni volta che cambia, il zipChanged il metodo sarà chiamato. Il zipChanged il metodo controllerà per vedere se la lunghezza del valore dello zip è 5. Quando raggiunge 5, il andare a prendere il metodo sarà chiamato. È qui che entra in gioco lo stub Sinon. A questo punto, $ .ajax è in realtà un mozzicone di Sinon. Così calledOnce sarà quindi vero nel test.

Il test finale che scriveremo è per quando i dati tornano dal servizio Geonames:

test ("dovrebbe impostare informazioni sulla città in base al risultato della ricerca", function () var address = new AddressViewModel (); address.fetched (postalcode: [adminCode1: "foo", adminName2: "bar", placeName: "bam "]); uguale (address.city ()," bam "); uguale (address.state ()," foo "); uguale (address.county ()," bar "););

Questo test metterà alla prova il modo in cui i dati dal server vengono impostati su AddressViewmodel. Eseguilo, guarda un po 'di rosso. Ora rendilo verde:

AddressViewModel.prototype.fetched = function (data) var cityInfo; if (data.postalcodes && data.postalcodes.length === 1) cityInfo = data.postalcodes [0]; this.city (cityInfo.placeName); this.state (cityInfo.adminCode1); this.county (cityInfo.adminName2); ;

Il metodo recuperato si limita a verificare l'esistenza di una matrice postalcodes nei dati dal server e quindi imposta le proprietà corrispondenti su ViewModel.

Vedi com'è facile ora? Una volta ottenuto il flusso di fare questo giù, ti troverai quasi mai voglia di farlo non TDD di nuovo. Finisci con delle belle funzioni che sono testabili. Ti costringi a pensare a come il tuo codice interagisce con le sue dipendenze. E ora hai una suite di test da eseguire quando vengono aggiunti altri nuovi requisiti al codice. Anche se ti manca qualcosa e c'è un bug nel codice, ora puoi semplicemente aggiungere un nuovo test alla suite, per provare che hai risolto il bug! In realtà finisce per essere un po 'avvincente.


Copertura di prova

La copertura del test fornisce un modo semplice per valutare quanto del tuo codice è stato testato da un test unitario. Spesso è difficile e non vale la pena di raggiungere il 100% di copertura, ma fai quello che puoi per ottenere il più alto possibile.

Una delle più nuove e più semplici librerie di copertura si chiama Blanket.js. Usarlo con QUnit è davvero semplice. Basta prendere il codice direttamente dalla propria homepage o installarlo con Bower. Quindi aggiungi coperta come libreria nella parte inferiore del tuo qunit.html file, quindi aggiungere Dati-cover a tutti i file per i test di copertura.

     

Fatto. Super facile, e ora avrai un'opzione nel tuo runner QUnit per mostrare la copertura:

In questo esempio, puoi vedere che la copertura del test non è del tutto al 100%, ma in questo caso poiché non c'è molto codice, sarà facile risalirlo. Puoi effettivamente eseguire il drill-down e vedere le funzioni esatte che non sono ancora state coperte:

Qui in questo caso, il FormViewModel non è mai stato istanziato nei test e quindi manca la copertura del test. È quindi possibile semplicemente aggiungere un nuovo test che crea un'istanza di FormViewModel, e forse scrivere un'affermazione che controlla che il indirizzo la proprietà è presente ed è un instanceof il AddressViewModel.

Avrai quindi il piacere di vedere una copertura di prova del 100%.


Test di complessità

Man mano che le tue applicazioni diventano sempre più grandi, è bello poter eseguire alcune analisi statiche sul codice JavaScript. Un ottimo strumento per eseguire analisi su JavaScript si chiama Platone.

Puoi correre Platone installandolo tramite npm con:

npm install -g plato

Quindi puoi correre Platone su una directory di codice JavaScript:

rapporti di plato -r -d js / app

Questo eseguirà Platone su tutto il codice JavaScript situato in "js / app"e produrre i risultati in rapporti. Platone esegue tutti i tipi di metriche sul codice, comprese le righe medie di codice, un punteggio di manutenibilità calcolato, JSHint, errori difficili, stimati e altro.

Non c'è molto da vedere in quell'immagine precedente, semplicemente perché per il codice su cui abbiamo lavorato, c'è solo un file, ma quando si inizia a lavorare con una grande applicazione che ha molti file e linee di codice , troverai le informazioni che ti danno estremamente utile.

Tiene anche traccia di tutte le volte che lo hai eseguito, così puoi vedere come cambiano le tue statistiche nel tempo.

Conclusione

Mentre testare il lato client sembra una proposta difficile, ci sono così tanti ottimi strumenti da usare in questi giorni per renderlo super facile. Questo articolo graffia a malapena la superficie di tutte le cose là fuori al giorno d'oggi per rendere facile il test lato client. Può essere un compito noioso, ma alla fine scoprirai che i vantaggi di avere una suite di test e un codice testabile superano di gran lunga il risultato. Si spera che con i passaggi illustrati qui, sarete in grado di iniziare a testare rapidamente il codice lato client.