Asigurându-vă că aplicația dvs. este testată, puteți reduce cantitatea de bug-uri găsite în codul dvs., puteți spori mentenabilitatea aplicației dvs. și puteți proiecta un cod bine structurat.
Testarea pe unitatea clientului prezintă diferite provocări decât testarea pe partea de server. Când se ocupă de codul de partea clientului, vă veți confrunta cu dificultăți în a separa logica aplicațiilor de logica DOM, precum și structurarea codului JavaScript în general. Din fericire, există o mulțime de biblioteci de test de mare parte a clientului, pentru a vă ajuta să vă testați codul, să creați valori privind acoperirea testului, precum și să analizați complexitatea acestuia.
În primul rând, testarea unităților, în general, este o modalitate de a reduce erorile, asigurându-vă că aplicația dvs. funcționează așa cum ar trebui. Dincolo de asta, sunt noțiunile de dezvoltare a testului de conducere (TDD) și de dezvoltare bazată pe comportament (BDD).
Aceste două strategii de testare a unităților vă vor ajuta să vă proiectați aplicația scriind teste inainte de scrieți logica aplicației. Prin scrierea testelor înainte de a scrie codul, vă dați ocazia să vă gândiți la proiectul aplicației.
Acest lucru se întâmplă deoarece atunci când scrieți teste, încercați în esență să proiectați API-ul pentru modul în care interacționați cu codul dvs., pentru a obține, prin urmare, o mai bună înțelegere a designului său. Testarea în primul rând vă va arăta rapid orice defecte pe care le aveți în design deoarece scrieți un cod de testare care utilizează în mod esențial codul pe care îl scrieți!
TDD este un proces de descoperire a codului
Veți afla că TDD vă ajută să descoperiți codul în timp ce îl scrieți. TDD este rezumată foarte rapid ca "Red, Green, Refactor". Ce înseamnă asta, scrieți un test, scrieți un cod suficient pentru a efectua testul eșua primul. Atunci, scrieți codul care face testul dvs. După aceea, gândiți-vă prin ceea ce tocmai ați scris și refăcut-o. Simplu și ușor.
BDD este o preluare ușoară a TDD și se bazează mai mult pe cerințele și specificațiile de afaceri.
Există multe motive pentru care ar trebui să testați codul dvs. de client. Așa cum am menționat anterior, va ajuta la reducerea erorilor și vă va ajuta să vă proiectați aplicația. Testarea pe partea clientului este, de asemenea, importantă, deoarece vă oferă șansa de a vă testa codul frontal, în mod izolat, departe de prezentarea dvs. Cu alte cuvinte, unul dintre avantajele sale este să testați codul JavaScript fără a răsturna într-adevăr un server de aplicații. Pur și simplu rulați testele și asigurați-vă că lucrurile funcționează fără să faceți clic și să testați lucrurile. În multe cazuri, nici măcar nu trebuie să aveți acces la internet, atâta timp cât testele dvs. sunt configurate corect.
Cu JavaScript, care are un rol atât de important în dezvoltarea web modernă, este important să învățați cum să testați codul și să reduceți șansele de a face bug-uri în codul de producție. Șeful tău nu-i place când se întâmplă asta și nici tu nu trebuie! De fapt, un loc bun pentru a începe să lucrați cu testarea pe partea clientului este de a scrie teste în jurul unui raport de eroare. Acest lucru vă va permite să obțineți teste de testare atunci când nu aveți un loc pentru a începe de la zero.
Un alt motiv pentru a testa codul dvs. de client este că, odată ce o suită de teste există și are o acoperire decentă asupra codului dvs., când vă pregătiți să mergeți și să adăugați noi caracteristici în codul dvs., veți putea să adăugați noua caracteristică - efectuați-vă testele și asigurați-vă că nu vă regresați și nu întrerupeți caracteristicile existente.
Noțiuni de bază cu testarea pe partea clientului poate fi descurajantă dacă nu ați făcut-o niciodată înainte. Una dintre cele mai dificile aspecte despre testarea pe partea clientului este găsirea celei mai bune modalități de a izola DOM de logica aplicației. Asta adesea înseamnă că vei avea nevoie de un fel de abstractizare peste DOM. Cea mai ușoară modalitate de a realiza acest lucru este printr-un cadru al clientului, cum ar fi Knockout.js, Backbone.js sau Angular.js, pentru a numi doar câteva.
Când utilizați o astfel de bibliotecă, puteți să vă gândiți mai puțin despre modul în care pagina dvs. se redă în browser și despre caracteristicile aplicației dvs. Nu este ca și cum nu este posibil să se testeze unitatea cu doar JavaScript simplu. În acest caz, viața dvs. va fi mult mai ușoară dacă proiectați codul astfel încât DOM să poată fi ușor abstractizat.
Există o mulțime de diferite biblioteci de testare pentru a alege de la, deși cei trei alergători din față tind să fie Qunit, Mocha și Jasmine.
Jasmine și Mocha sunt ambii de la școala BDD de testare a unităților, în timp ce Qunit este doar un cadru de testare a unității propriu.
Pentru restul postului, vom explora folosind Qunit ca barieră pentru intrarea în testarea pe partea clientului este foarte scăzută. Consultați acest intro detaliat la QUNN pentru mai multe informații.
Noțiuni de bază cu Qunit este extrem de simplu. Următorul cod HTML este tot ce aveți nevoie:
Exemplu de încercare
Pentru următoarele exemple, să presupunem că construim un widget mic pe care introduceți un cod poștal într-o casetă de text și returnează valorile corespunzătoare ale orașului, statului și județului folosind Geonames. Va apărea doar un cod poștal la început, dar de îndată ce codul poștal are cinci caractere, acesta va prelua datele de la Geonames. Dacă este capabil să găsească date, va afișa câțiva câmpuri care conțin informațiile despre oraș, stat și județ. Vom folosi și Knockout.js. Primul pas este de a scrie un test de eșec.
Gândindu-ne prin proiect cu puțin înainte de primul test, este probabil necesar să existe cel puțin două modele de vizualizare, astfel încât acesta să fie un bun punct de plecare. Pentru a începe, vom defini un modul QUnit și primul nostru test:
modul ("retroproiector de coduri poștale"); test ("modelele de vizualizare ar trebui să existe", funcția () ok (FormViewModel, "Un model de vizualizare pentru formularul nostru ar trebui să existe"); ok (AddressViewModel, "Un model de vedere pentru adresa noastră ar trebui să existe");
Dacă executați acest test, acesta va eșua, acum puteți să scrieți codul pentru a trece:
var Adresa AddressViewModel = funcție (opțiuni) ; var FormViewModel = funcție () this.address = new AdresaViewModel (); ;
În acest moment veți vedea mai degrabă verde decât roșu. Testele de genul asta par la început un pic prost, dar sunt utile prin faptul că te obligă să te gândești cel puțin la unele din primele etape ale designului tău.
Următorul test pe care îl vom scrie va lucra la AddressViewModel
lui. Știm din specificațiile acestui widget că celelalte câmpuri ar trebui să fie ascunse la început, până când se găsesc datele pentru codul poștal.
modul ("model de vizualizare a adreselor"); test ("ar trebui să afișeze datele de stat în oraș dacă se găsește un cod poștal"), function () var address = new AdresaViewModel (); ok (! address.isLocated ()); address.zip (12345); address.city foo "); adresa.state (" bar "); adresa.county (" bam "); ok (adresa.isLocat ()););
Nici unul din codul pentru aceasta nu a fost scris încă, dar ideea aici este că este localizat
va fi o observabilă calculată, care se va întoarce Adevărat
numai atunci când zipul, orașul, statul și județul sunt toate trut. Deci, acest test va da greșit la început, acum să scriem codul pentru a trece.
var AddressViewModel = funcție (opțiuni) opțiuni = opțiuni || ; this.zip = ko.observable (opțiuni.zip); this.city = ko.observable (opțiuni.citate); this.state = ko.observable (opțiuni.state); this.county = ko.observable (opțiuni.county); this.isLocated = ko.computed (funcția () return this.city () && this.state () && this.county () && this.zip ();, aceasta); this.initialize (); ;
Acum, dacă executați din nou testele, veți vedea verde!
Aceasta este, în modul cel mai de bază, modul în care puteți utiliza TDD pentru a scrie testele de capăt. În mod ideal, după fiecare încercare de eșec, ați scrie cel mai simplu cod care va face testul și apoi să vă întoarceți și să refaceți codul. Puteți învăța însă mai multe despre practicile TDD, așadar vă sugerăm să le citiți și să le studiați în continuare, dar exemplele anterioare sunt suficiente pentru a vă ajuta să vă gândiți mai întâi la scrierea testelor.
Sinon.js este o bibliotecă JavaScript care oferă posibilitatea de a spiona, stub și mock obiecte JavaScript. La testarea unităților de testare doriți să vă asigurați că aveți posibilitatea de a testa numai o anumită "unitate" de cod. Aceasta de multe ori înseamnă că va trebui să faci un fel de batjocură sau stubbing de dependențe pentru a izola codul testat.
Sinon are un API extrem de simplu pentru a face acest lucru. API-ul Geonames suportă extragerea datelor prin intermediul unui punct final JSONP, ceea ce înseamnă că vom putea să le folosim cu ușurință $ .ajax
.
În mod ideal, totuși, în testele dvs. nu va trebui să depindeți de API-ul Geonames. Acestea ar putea fi temporar în jos, internetul dvs. poate muri, și este, de asemenea, doar mai lent pentru a face efectiv apel ajax. Sinon pentru salvare.
test ("ar trebui să încercați doar să obțineți date dacă există 5 caractere"), funcție () var address = new AdresaViewModel (); sinon.stub (jQuery, "ajax") returns (done: $ .noop .zip (1234); ok (! jQuery.ajax.calledOnce); adresa.zip (12345); ok (jQuery.ajax.calledOnce); jQuery.ajax.restore (););
Aici, în acest test, facem câteva lucruri. Mai întâi de toate, sinon.stub
funcția este de fapt de gând să proxy peste jQuery.ajax
și adăugați capacitatea de a vedea de câte ori a fost numită și multe alte afirmații. După cum se arată în test, "ar trebui doar să încercați să obțineți date dacă există 5 caractere", vom presupune că atunci când adresa este setată doar la"1234
", că nici un apel ajax nu a fost făcut încă, apoi l-ați pus la"12345
", iar prin acest punct ar trebui să se facă un apel ajax.
Apoi trebuie să restaurăm jQuery.ajax
la starea inițială, pentru că suntem cetățeni buni ai testelor unitare și dorim să păstrăm testele noastre atomice. Menținerea testelor dvs. atomice este importantă pentru a se asigura că un test nu depinde de un alt test și nu există o stare comună între teste. Ele pot fi apoi executate în orice ordine, de asemenea.
Acum că testul este scris, îl putem rula, îl putem urmări și apoi scrie codul care efectuează solicitarea ajax către Geonames.
AdresaViewModel.prototype.initialize = funcția () this.zip.subscribe (aceasta.zipChanged, aceasta); ; AdresaViewModel.prototype.zipChanged = funcție (valoare) if (value.toString () .dată === 5) this.fetch (value); ; Adresa URLViewModel.prototype.fetch = funcția (zip) var baseUrl = "http://www.geonames.org/postalCodeLookupJSON" $ .ajax (url: baseUrl, data: "postalcode" noi ", tastați:" GET ", dataType:" JSONP ") făcut (this.fetched.bind (this)); ;
Aici ne abonați la modificările codului poștal. Ori de câte ori se schimbă, zipChanged
se va numi metoda. zipChanged
metoda va verifica dacă lungimea valorii zip-ului este 5
. Când ajunge 5
, aduce
se va numi metoda. Iată în cazul în care Ston Sinon vine pentru a juca. In acest punct, $ .ajax
este de fapt un stâlp Sinon. Asa de calledOnce
va fi atunci Adevărat
în test.
Testul final pe care îl vom scrie este atunci când datele revin din serviciul Geonames:
test ("ar trebui să stabilească informații despre oraș pe baza rezultatelor căutării", funcție () var address = new AdresaViewModel (); address.fetched (postalcodes: [adminCode1: "foo", adminName2: "bar", placeName: ")), egal (adresa.citate ()," bam "), egal (adresa.state ()," foo ");
Acest test va testa modul în care datele de pe server sunt setate pe AddressViewmodel
. Fugi, vezi roșu. Acum faceți-o verde:
AdresaViewModel.prototype.fetched = funcția (date) var cityInfo; dacă (date.postalcodes && data.postalcodes.length === 1) cityInfo = date.postalcodes [0]; this.city (cityInfo.placeName); this.state (cityInfo.adminCode1); this.county (cityInfo.adminName2); ;
Metoda preluată asigură doar că există o serie de elemente postalcodes
în datele de pe server și apoi stabilește proprietățile corespunzătoare pe viewModel
.
Vedeți cât de ușor este acum? Odată ce veți obține fluxul de a face acest lucru în jos, veți găsi pe care nu vă doriți niciodată nu TDD din nou. Încheiați cu mici funcții mici care pot fi testate. Te forțezi să te gândești la modul în care codul tău interacționează cu dependențele sale. Și acum aveți o serie de teste pentru a rula atunci când se adaugă o altă cerință nouă în cod. Chiar dacă vă pierdeți ceva și există o eroare în cod, acum puteți adăuga un nou test la suită, pentru a dovedi că ați rezolvat problema! De fapt, el devine un fel de dependență.
Analiza de testare oferă o modalitate ușoară de a evalua cât de mult din codul dvs. a fost testat printr-un test de unitate. Este adesea greu și nu merită să ajungă la o acoperire de 100%, dar faceți tot ce puteți pentru a obține cât mai mare posibil.
Una dintre bibliotecile de acoperire mai noi și mai ușoare se numește Blanket.js. Folosirea lui cu Qunit este moartă simplu. Pur și simplu apuca codul de pe pagina de pornire sau îl instalați cu Bower. Apoi adăugați pătură ca o bibliotecă în partea de jos a dvs. qunit.html
fișier, apoi adăugați date de acoperire
la toate fișierele pe care doriți să le efectuați testele de acoperire.
Terminat. Super ușor, iar acum veți primi o opțiune în alergătorul dvs. QUnit pentru a afișa acoperirea:
În acest exemplu, puteți observa că acoperirea testului nu este destul de 100%, dar în acest caz, deoarece nu există prea multe coduri, va fi ușor să o ridicați. Puteți să vă descurcați și să vedeți exact funcțiile care nu au fost încă acoperite:
Aici, în acest caz, FormViewModel
nu a fost niciodată instanțiată în teste și, prin urmare, lipsește acoperirea testului. Puteți adăuga apoi un test nou care creează o instanță a FormViewModel
, și poate scrie o afirmație care verifică faptul că adresa
proprietatea este prezentă și este una instanță de
AddressViewModel
.
Veți avea apoi plăcerea de a vedea 100% acoperire de testare.
Pe măsură ce aplicațiile dvs. devin tot mai mari, este frumos să puteți efectua o analiză statică a codului dvs. JavaScript. Un instrument excelent pentru rularea analizei pe JavaScript se numește Platon.
Poți alerga Plato
prin instalarea acestuia prin NPM
cu:
npm install -g plato
Atunci poți alerga Plato
pe un director de cod JavaScript:
plato -r -d js / rapoarte aplicație
Acest lucru va rula Platon pe toate JavaScript-ul situat la "js / app
"și să obțină rezultatele rapoarte
. Plato rulează tot felul de valori pe codul dvs., inclusiv linii medii de cod, un scor de întreținere calculat, JSHint, erori greșite, estimate și multe altele.
Nu este o mulțime de a vedea în acea imagine anterioară, pur și simplu pentru că pentru codul pe care am lucrat, există doar un singur fișier, dar atunci când intră în lucrul cu o aplicație mare, care are o mulțime de fișiere și linii de cod , veți găsi informațiile extrem de utile.
Chiar ține evidența tuturor timpurilor pe care le-ați executat, pentru a vedea cum se schimbă statisticile dvs. în timp.
În timp ce testarea partea clientului pare a fi o propunere dificilă, există atât de multe instrumente excelente pentru a le folosi în aceste zile pentru a le face super ușor. Acest articol abia scarpină suprafața tuturor lucrurilor existente în zilele noastre pentru a face testarea pe partea clientului ușor. Poate fi o sarcină plictisitoare, dar veți găsi că, în cele din urmă, beneficiile de a avea o suită de testare și un cod testabil depășesc cu mult. Sperăm că, cu pașii prezentați aici, veți putea începe testarea rapidă a codului de pe partea clientului.