Primul tău tutorial pentru aplicația AngularJS Partea 2: Instrumente pentru schele, construcție și testare

Publicat: 2022-03-11

Introducere

Cu numeroasele instrumente disponibile pentru a ajuta la dezvoltarea aplicațiilor AngularJS, mulți oameni au impresia că este un cadru extrem de complicat, ceea ce nu este deloc așa. Acesta este unul dintre motivele principale pentru care am început această serie de tutoriale.

În prima parte am acoperit elementele de bază ale cadrului AngularJS și am început prin a scrie prima noastră aplicație. Această postare este concepută pentru începători. Dacă sunteți un dezvoltator AngularJS mai experimentat, s-ar putea să fiți mai interesat de directivele de demistificare sau de o poveste despre AngularJS în uz la o pornire în creștere.

În acest tutorial, vom lăsa deoparte stratul logic al aplicației și vom învăța cum să desfășurăm configurarea corectă a proiectului AngularJS, inclusiv schelele, gestionarea dependenței și pregătirea acestuia pentru testare (atât unitate, cât și end-to-end). Vom face acest lucru folosind aceste instrumente AngularJS: Yeoman, Grunt și Bower. Apoi, vom revizui procesul de scriere și rulare a testelor Jasmine folosind Karma.

Karma, Jasmine, Grunt, Bower, Yeoman... Care sunt toate aceste instrumente?

Există atât de multe instrumente de dezvoltare pentru a ajuta la schelele AngularJS, la testarea AngularJS și la construirea corectă a unei aplicații.

Dacă lucrați cu JavaScript, este foarte probabil să cunoașteți deja cel puțin unele dintre aceste instrumente, chiar dacă sunteți nou la Angular. Dar pentru a asigura o bază comună, voi evita să fac presupuneri. Să trecem în revistă pe scurt fiecare dintre aceste tehnologii și pentru ce este utilă:

  • Karma (cunoscută anterior ca Testacular) este testul JavaScript al Google și alegerea naturală pentru testarea AngularJS. Pe lângă faptul că vă permite să rulați testele pe browsere reale (inclusiv browsere pentru telefon/tabletă), este, de asemenea , agnostic cadrul de testare ; ceea ce înseamnă că îl puteți utiliza împreună cu orice cadru de testare la alegere (cum ar fi Jasmine, Mocha sau QUnit, printre altele).

  • Jasmine va fi cadrul nostru de testare de alegere, cel puțin pentru această postare. Sintaxa sa este destul de similară cu cea a RSpec, dacă ați lucrat vreodată cu asta. (Dacă nu ați făcut-o, nu vă faceți griji; îl vom verifica mai detaliat mai târziu în acest tutorial.)

  • Grunt este un ruler de sarcini care ajută la automatizarea mai multor sarcini repetitive, cum ar fi minificarea, compilarea (sau construirea), testarea și configurarea unei previzualizări a aplicației dvs. AngularJS.

  • Bower este un manager de pachete care vă ajută să găsiți și să instalați toate dependențele aplicației, cum ar fi cadrele CSS, bibliotecile JavaScript și așa mai departe. Se rulează peste git, la fel ca Rails bundler și evită nevoia de a descărca și actualiza manual dependențele.

  • Yeoman este un set de instrumente care conține 3 componente de bază: Grunt, Bower și instrumentul de schelă Yo. Yo generează cod boilerplate cu ajutorul generatoarelor (care sunt doar șabloane de schele) și configurează automat Grunt și Bower pentru proiectul tău. Puteți găsi generatoare pentru aproape orice cadru JavaScript (Angular, Backbone, Ember etc.), dar deoarece ne concentrăm aici pe Angular, vom folosi proiectul generator-angular.

Deci, de unde începem?

Ei bine, primul lucru pe care trebuie să-l facem este să instalăm instrumentele de care vom avea nevoie.

Dacă nu aveți deja instalate git, node.js și npm, mergeți mai departe și instalați-le.

Apoi vom merge la linia de comandă și vom rula următoarea comandă pentru a instala instrumentele lui Yeoman:

 npm install -g yo grunt-cli bower

Ah, și nu uitați, vom folosi generatorul AngularJS, așa că va trebui să îl instalați și:

 npm install -g generator-angular

OK, acum suntem gata să...

Scaffold/generați aplicația noastră AngularJS

Ultima dată, am împrumutat manual codul nostru standard din proiectul de semințe unghiulare. De data aceasta, vă vom lăsa pe yo (împreună cu generatorul-unghiular) să facă asta pentru noi.

Tot ce trebuie să facem este să creăm noul nostru folder de proiect, să navigăm la el și să rulăm:

 yo angular

Ne vor fi prezentate câteva opțiuni, cum ar fi dacă să includem sau nu Bootstrap și Compass. Deocamdată, să spunem nu lui Compass și da Bootstrap. Apoi, când vi se solicită ce module să includem (resurse, cookie-uri, sanitize și ruta), vom selecta doar angular-route.js .

Proiectul nostru ar trebui acum creat (poate dura un minut), integrat cu Karma și totul pre-configurat.

Notă: Rețineți că limităm modulele aici la cele pe care le-am folosit în aplicația pe care am construit-o în prima parte a acestui tutorial. Când faceți acest lucru pentru propriul proiect, va depinde de dvs. să determinați ce module va trebui să includeți.

Acum, deoarece vom folosi Jasmine, să adăugăm adaptorul karma-jasmine la proiectul nostru:

 npm install karma-jasmine --save-dev

În cazul în care dorim ca testele noastre să fie executate pe o instanță Chrome, să adăugăm karma-chrome-launcher :

 npm install karma-chrome-launcher --save-dev

OK, dacă am făcut totul corect, arborele nostru de fișiere de proiect ar trebui să arate acum astfel:

Un exemplu de arbore de fișiere de proiect care utilizează aceste instrumente AngularJS va arăta astfel.

Codul aplicației noastre static intră în directorul app/ și directorul test/ va conține (da, ați ghicit!) testele noastre. Fișierele pe care le vedem pe rădăcină sunt fișierele noastre de configurare a proiectului. Sunt multe de învățat despre fiecare dintre ele, dar deocamdată ne vom menține doar cu configurația implicită. Deci, să rulăm aplicația noastră pentru prima dată, ceea ce o putem face pur și simplu cu următoarea comandă:

 grunt serve

Și voila! Aplicația noastră ar trebui să apară acum în fața noastră!

Câteva despre Bower pentru AngularJS

Înainte de a intra în partea cu adevărat importantă (adică, testarea), să luăm un minut pentru a afla ceva mai multe despre Bower. După cum am menționat mai devreme, Bower este managerul nostru de pachete. Adăugarea unei lib sau plugin la proiectul nostru se poate face pur și simplu folosind comanda bower install . De exemplu, pentru a include modernizr , tot ce trebuie să facem este următoarele (în directorul nostru de proiecte, desigur):

 bower install modernizr

Rețineți, totuși, că, deși acest lucru face ca modernizr să facă parte din proiectul nostru (va fi localizat în directorul app/bower_components ), suntem totuși responsabili să îl includem în aplicația noastră (sau să gestionăm când ar trebui inclus), așa cum am avea nevoie. de a face cu orice lib adăugată manual. O modalitate de a face acest lucru ar fi să adăugați pur și simplu următoarea etichetă <script> la index.html :

 <script src="bower_components/modernizr/modernizr.js"></script>

Alternativ, putem folosi fișierul bower.json pentru a ne gestiona dependențele. După ce ați urmat cu atenție fiecare pas până acum, fișierul bower.json ar trebui să arate astfel:

 { "name": "F1FeederApp", "version": "0.0.0", "dependencies": { "angular": "1.2.15", "json3": "~3.2.6", "es5-shim": "~2.1.0", "jquery": "~1.11.0", "bootstrap": "~3.0.3", "angular-route": "1.2.15" }, "devDependencies": { "angular-mocks": "1.2.15", "angular-scenario": "1.2.15" } }

Sintaxa este destul de explicită, dar mai multe informații sunt disponibile aici.

Putem apoi adăuga orice dependențe noi suplimentare pe care le dorim și apoi tot ce avem nevoie este următoarea comandă pentru a le instala:

 bower install

Acum să scriem câteva teste!

OK, acum este timpul să reluăm de unde am rămas în prima parte și să scriem câteva teste pentru aplicația noastră AngularJS.

Dar mai întâi, există o mică problemă pe care trebuie să o rezolvăm: deși dezvoltatorii generator-angular și-au bazat șablonul de proiect pe proiectul angular-seed (care este boilerplate oficial Angular), dintr-un motiv oarecare nu înțeleg cu adevărat, au decis pentru a modifica convențiile de denumire a folderului app (schimbarea css în styles , js în scripts și așa mai departe).

Drept urmare, aplicația pe care am scris-o inițial are acum căi care nu sunt conforme cu schela pe care tocmai am generat-o. Pentru a ocoli acest lucru, haideți să descarcăm codul aplicației de aici și să lucrăm cu acea versiune din acest moment încolo (în mare parte este exact aceeași aplicație pe care am scris-o inițial, dar cu căile actualizate pentru a se potrivi cu denumirea unghiulară a generatorului).

După descărcarea aplicației, navigați la folderul tests/spec/controllers și creați un fișier numit drivers.js care conține următoarele:

 describe('Controller: driversController', function () { // First, we load the app's module beforeEach(module('F1FeederApp')); // Then we create some variables we're going to use var driversController, scope; beforeEach(inject(function ($controller, $rootScope, $httpBackend) { // Here, we create a mock scope variable, to replace the actual $scope variable // the controller would take as parameter scope = $rootScope.$new(); // Then we create an $httpBackend instance. I'll talk about it below. httpMock = $httpBackend; // Here, we set the httpBackend standard reponse to the URL the controller is // supposed to retrieve from the API httpMock.expectJSONP( "http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK").respond( {"MRData": {"StandingsTable": {"StandingsLists" : [{"DriverStandings":[ { "Driver": { "givenName": 'Sebastian', "familyName": 'Vettel' }, "points": "397", "nationality": "German", "Constructors": [ {"name": "Red Bull"} ] }, { "Driver": { "givenName": 'Fernando', "familyName": 'Alonso' }, "points": "242", "nationality": "Spanish", "Constructors": [ {"name": "Ferrari"} ] }, { "Driver": { "givenName": 'Mark', "familyName": 'Webber' }, "points": "199", "nationality": "Australian", "Constructors": [ {"name": "Red Bull"} ] } ]}]}}} ); // Here, we actually initialize our controller, passing our new mock scope as parameter driversController = $controller('driversController', { $scope: scope }); // Then we flush the httpBackend to resolve the fake http call httpMock.flush(); })); // Now, for the actual test, let's check if the driversList is actually retrieving // the mock driver array it('should return a list with three drivers', function () { expect(scope.driversList.length).toBe(3); }); // Let's also make a second test checking if the drivers attributes match against // the expected values it('should retrieve the family names of the drivers', function () { expect(scope.driversList[0].Driver.familyName).toBe("Vettel"); expect(scope.driversList[1].Driver.familyName).toBe("Alonso"); expect(scope.driversList[2].Driver.familyName).toBe("Webber"); }); });

Aceasta este suita de teste pentru driverscontroller -ul nostru. Poate arăta ca o mulțime de cod, dar cea mai mare parte este de fapt doar o declarație de date simulată. Să aruncăm o privire rapidă la elementele cu adevărat importante:

  • Metoda describe() definește suita noastră de teste.
  • Fiecare it() este o specificație de test adecvată.
  • Fiecare beforeEach() este executată chiar înainte de fiecare dintre teste.

Cel mai important (și potențial confuz) element aici este serviciul $httpBackend pe care l-am instanțiat pe variabila httpMock . Acest serviciu acționează ca un back-end fals și răspunde la apelurile noastre API în timpul testelor, la fel cum ar face serverul nostru real în producție. În acest caz, folosind funcția expectJSONP() , o setăm să intercepteze orice solicitări JSONP către adresa URL dată (aceeași pe care o folosim pentru a obține informațiile de la server) și, în schimb, returnăm o listă statică cu trei drivere, mimând răspunsul serverului real. Acest lucru ne permite să știm cu siguranță ce ar trebui să se întoarcă de la controler. Prin urmare, putem compara rezultatele cu cele așteptate, folosind funcția expect() . Dacă se potrivesc, testul va trece.

Rularea testelor se face pur și simplu cu comanda:

 grunt test

Suita de testare pentru controlerul detaliilor driverului ( drivercontroller ) ar trebui să fie destul de asemănătoare cu cea pe care tocmai am văzut-o. Îți recomand să încerci să-ți dai seama singur ca exercițiu (sau poți să arunci o privire aici, dacă nu ești la îndemână).

Dar testele AngularJS end-to-end?

Echipa Angular a introdus recent un nou alergător pentru teste end-to-end numit Protractor. Utilizează webdriver pentru a interacționa cu aplicația care rulează în browser și, de asemenea, folosește cadru de testare Jasmine în mod implicit, astfel încât sintaxa va fi foarte consistentă cu cea a testelor noastre unitare.

Deoarece Protractor este un instrument destul de nou, integrarea sa cu stiva Yeoman și generator-angular necesită încă o cantitate destul de mare de muncă de configurare. Având în vedere asta și intenția mea de a păstra acest tutorial cât mai simplu posibil, planul meu este să dedic o postare viitoare exclusiv pentru a acoperi în profunzime testările end-to-end în AngularJS.

Concluzie

În acest moment al seriei de tutoriale, am învățat cum să schelele aplicația noastră Angular cu yo , să gestionăm dependențele acesteia cu bower și să scriem/execuțim câteva teste folosind karma și protractor . Țineți minte, totuși, că acest tutorial este menit doar ca o introducere la aceste instrumente și practici AngularJS; nu am analizat nici unul dintre ele aici în profunzime.

Scopul nostru a fost pur și simplu să vă ajutăm să începeți pe această cale. De aici, depinde de tine să mergi mai departe și să înveți tot ce poți despre acest cadru uimitor și suită de instrumente.

Addendum: Câteva note (importante) de la autor

După ce au citit acest tutorial, unii oameni ar putea întreba: „Așteaptă. Nu ar trebui să faci toate aceste lucruri înainte de a începe să codificați aplicația? Nu ar fi trebuit aceasta să fie prima parte a acestui tutorial?”

Răspunsul meu scurt la asta este nu . După cum am văzut în prima parte, nu trebuie de fapt să știți toate aceste lucruri pentru a vă codifica prima aplicație Angular. Mai degrabă, majoritatea instrumentelor pe care le-am discutat în această postare sunt concepute pentru a vă ajuta să vă optimizați fluxul de lucru de dezvoltare și să practicați Dezvoltarea bazată pe teste (TDD).

Și vorbind despre TDD, cel mai de bază concept de TDD este cu siguranță unul solid; și anume, scrieți testele înainte de a vă scrie codul. Unii oameni, totuși, duc acest concept mult prea departe. TDD este o practică de dezvoltare, nu o metodă de învățare. În consecință, scrierea testelor înainte de a scrie codul are foarte mult sens, în timp ce învățarea cum să scrieți testele înainte de a învăța cum să codificați nu are sens.

Personal cred că acesta este motivul principal pentru care tutorialele oficiale Angular se pot simți atât de complicate și pot fi aproape imposibil de urmat pentru persoanele fără experiență anterioară MVC/TDD front-end. Acesta este unul dintre motivele principale pentru care am început această serie de tutoriale.

Sfatul meu personal pentru cei care învață să navigheze în lumea AngularJS este: Nu fi prea dur cu tine. Nu trebuie să înveți totul dintr-o dată (în ciuda faptului că oamenii îți spun contrariul!). În funcție de experiența dumneavoastră anterioară cu alte cadre front-end/de testare, AngularJS poate fi destul de greu de înțeles inițial. Așadar, învață tot ce trebuie să înveți până când poți să scrii propriile aplicații simple și apoi, odată ce te simți confortabil cu elementele de bază ale cadrului, te poți preocupa să selectezi și să aplici practicile de dezvoltare pe termen lung care funcționează cel mai bine pentru tu.

Desigur, aceasta este părerea mea umilă și nu toată lumea va fi de acord cu această abordare (și echipa de dezvoltatori Angular poate trimite un criminal angajat după mine odată ce public asta), dar aceasta este viziunea mea și sunt destul de sigur că sunt mulți oameni. acolo cine va fi de acord cu mine.

Înrudit: Tutorial Angular 6: Caracteristici noi cu putere nouă