Da jeg begynte å leke med Ember.js for nesten et år siden, viste testbarhetshistorien noe å være ønsket. Du kan prøve å teste et objekt uten problemer, men en enhetstest er bare en måte å få tilbakemelding når du bygger et programvareprodukt. I tillegg til enhetstester ønsket jeg en måte å verifisere integrering av flere komponenter på. Så som de fleste testet rike JavaScript-applikasjoner, nådde jeg for moren til alle testverktøy, Selen.
Nå før jeg bash det, uten en riktig introduksjon, er det verdt å nevne at Selen er en fin måte å verifisere hele webapplikasjonen din, fungerer med en full produksjonslignende database og alle dine produksjonsavhengigheter, etc. Og fra et QA-perspektiv, er dette verktøyet kan være en god ressurs for lag som trenger end-to-end UI-aksepttester.
Men over tid kan en tilsynelatende liten testpakke bygget på Selen begynne å dra hastigheten til laget ditt til et snegltakthastighet. En enkel måte å redusere denne smerten på er å unngå å bygge en stor applikasjon i utgangspunktet. Hvis du bygger en håndfull mindre webapplikasjoner i stedet, kan det være med til å holde deg flytende for litt lenger fordi ingen enkeltbygging vil knuse laget, mens du vokser.
Men selv på et lite prosjekt er det virkelige problemet med Selen at det ikke er en del av den testdrevne utviklingsprosessen. Når jeg gjør rød / grønn / refactor, har jeg ikke tid til sakte tilbakemelding i noen form. Jeg trengte en måte å skrive både enhet og integrasjonstester på som ville gi rask tilbakemelding for å hjelpe meg til å forme programvaren jeg skrev på en mer iterativ måte. Hvis du bruker en versjon av Ember.js> = RC3, har du lykke, fordi du skriver en enhet eller integreringstest er en tur i delen.
Nå som vi kan skrive JavaScript-tester for vår søknad, hvordan utfører vi dem? De fleste utviklere starter ut med nettleseren direkte, men fordi jeg ønsket noe jeg kunne utføre headless fra kommandolinjen i et CI miljø med et rikt økosystem fullt av plugins, så jeg Karma.
Det jeg likte Karma er at det bare vil være testløperen din. Det bryr seg ikke om hvilken JavaScript-testramme du bruker eller hvilken klientside MVC-rammeverk du bruker. Det er enkelt å komme i gang med og skrive tester som utfører mot produksjonen din Ember.js-applikasjonen er bare noen få linjer med konfigurasjon.
Men før vi kan konfigurere Karma, må vi installere den ved hjelp av npm. Jeg anbefaler at du installerer den lokalt, slik at du kan holde npm-modulene dine isolert per prosjekt. For å gjøre dette, legg til en fil med navnet package.json
'til roten til prosjektet ditt som ser noe ut som nedenfor.
"avhengigheter": "karma-qunit": "*", "karma": "0.10.2"
Dette eksemplet krever både Karma og et plugin for QUnit. Etter at du har lagret package.json
filen ovenfor, slipp tilbake til kommandolinjen og skriv inn npm installasjon
å trekke ned de nødvendige nodemodulene.
Etter at npm-installasjonen er fullført, vil du nå se en ny mappe med navnet node_modules
i roten til prosjektet ditt. Denne mappen inneholder all JavaScript-koden vi nettopp trakk ned med npm, inkludert Karma og QUnit-plugin. Hvis du driller deg enda lenger til node_modules / karma / bin /
Du vil se Karma kjørbar. Vi skal bruke dette til å konfigurere testløperen, utføre tester fra kommandolinjen, osv.
Neste må vi konfigurere karma så det vet hvordan å utføre QUnit-testene. Type karma init
fra roten til prosjektet. Du vil bli bedt om en liste over spørsmål. Den første vil spørre hvilken testramme du vil bruke, hit Tab til du ser qunit
, deretter treffer Tast inn. Neste svar Nei
til Question.js-spørsmålet, da vi ikke vil bruke det til denne prøveapplikasjonen. Tab til du ser PhantomJS for det tredje spørsmålet, og du må treffe Tast inn to ganger da det tillater flere alternativer her. Som for resten, bare la dem stå på standardinnstillingen.
Når du er ferdig, bør du se at Karma har generert en konfigurasjonsfil som heter karma.conf.js
i roten eller prosjektet ditt. Hvis du vil lese mer om de ulike alternativene som Karma støtter, kan du finne kommentarene som er nyttige. For dette eksempelets skyld har jeg en forenklet versjon av konfigurasjonsfilen for å holde ting nybegynnerlig.
Hvis du vil følge med, sletter du den genererte konfigurasjonsfilen og erstatter den med denne.
modul.exports = funksjon (karma) karma.set (basePath: 'js', filer: ["leverandør / jquery / jquery.min.js", "leverandør / styrer / handlebars.js", "leverandør / ember / ember.js "," leverandør / jquery-mockjax / jquery.mockjax.js "," app.js "," tester / *. js "), logLevel: karma.LOG_ERROR, nettlesere: ['PhantomJS'], singleRun: true, autoWatch: false, frames: ["qunit"]); ;
Dette skal være ganske lik det som Karma genererte tidligere, jeg har nettopp fjernet alle kommentarene og kuttet ut noen alternativer som vi ikke bryr oss om akkurat nå. For å skrive den første enhetstesten måtte jeg fortelle Karma litt mer om prosjektstrukturen.
På toppen av konfigurasjonsfilen ser du at jeg har satt basePath
til js
fordi alle JavaScript-eiendelene lever under denne mappen i prosjektet. Deretter fortalte jeg Karma hvor det kan finne JavaScript-filene som kreves for å teste vår enkle applikasjon. Dette inkluderer jQuery, Handlebars, Ember.js og app.js
filen selv.
Nå kan vi legge til den første enhetstestfilen til prosjektet. Først må du lage en ny mappe som heter tester
og nest den under js
mappe. Legg til en fil i denne nye katalogen som heter unit_tests.js
Det ser noe ut som dette.
test ('hallo verden', funksjon () like (1, 1, "";);
Denne testen gjør ikke noe verdifullt ennå, men det vil hjelpe oss med å verifisere at vi har alt koblet opp med Karma for å utføre det riktig. Legg merke til i Karma filer
delen, har vi allerede lagt til JS / tester
katalogen. På denne måten vil Karma trekke inn alle JavaScript-filer vi bruker til å teste vår søknad med, fremover.
Nå som vi har Karma konfigurert riktig, utfør qunit tester fra kommandolinjen ved hjelp av ./ node_modules / karma / bin / karma start
.
Hvis du har alt riktig konfigurert, bør du se Karma utføre en test og det lykkes. For å bekrefte det utført testen vi nettopp har skrevet, gjør det mislykkes ved å endre likestillingen. For eksempel kan du gjøre følgende:
test ('hallo verden', funksjon () like (1, 2, "boom"););
Hvis du kan mislykkes og gjøre det igjen, er det på tide å skrive en prøve med litt mer hensikt.
Men før vi begynner, kan vi diskutere prøveapplikasjonen som brukes i dette innlegget. I skjermbildet under ser du at vi har et veldig enkelt rutenett av brukere. I HTML-tabellen vises hver bruker etter fornavn sammen med en knapp for å slette den aktuelle brukeren. Øverst på applikasjonen vil du se et innspill for fornavn, etternavn og til slutt en knapp som vil legge til en annen bruker i tabellen når du klikker.
https://dl.dropboxusercontent.com/u/716525/content/images/2013/pre-tuts.png
Eksempelprogrammet har tre problemer. Først vil vi vise brukerens for- og etternavn, ikke bare fornavnet. Deretter fjerner du ikke brukeren når du klikker en sletteknapp. Og til slutt, når du legger til et fornavn, etternavn og klikk legg til, vil det ikke sette en annen bruker inn i bordet.
På overflaten ser det ut til å være det enkleste navnet endringen. Det viste seg også å være et godt eksempel som viser når du skal skrive en enhetstest, en integreringstest eller begge deler. I dette eksemplet er den raskeste måten å få tilbakemelding på å skrive en enkel enhetstest som hevder at modellen har en beregnet egenskap fullt navn
.
Enhetstesting av et ember-objekt er enkelt, du oppretter bare en ny forekomst av objektet og ber om fullt navn
verdi.
test ('fullName-egenskap returnerer både første og siste', funksjon () var person = App.Person.create (firstName: 'toran', lastName: 'billups'); var result = person.get ('fullName' ); lik (resultat, "toran billups", "fullName var" + resultat););
Neste hvis du går tilbake til kommandolinjen og kjører ./ node_modules / karma / bin / karma start
, det skal vise en feiltest med en nyttig beskjed som beskriver fullt navn
som udefinert i øyeblikket. For å fikse dette må vi åpne app.js
fil og legg til en beregnet eiendom til modellen som returnerer en streng av de kombinerte for- og etternavnet verdiene.
App.Person = Ember.Object.extend (firstName: ", lastName:", fullName: funksjon () var firstName = this.get ('firstName'); var lastName = this.get ('lastName') firstName + "+ lastName; .property ());
Hvis du går tilbake til kommandolinjen og kjører ./ node_modules / karma / bin / karma start
Du bør nå se en bestått enhetsprøve. Du kan utvide dette eksemplet ved å skrive noen andre enhetstester for å vise at den beregnede egenskapen skal endres når enten for- eller etternavnet er oppdatert på modellen.
test ('fullName-egenskap returnerer både første og siste', funksjon () var person = App.Person.create (firstName: 'toran', lastName: 'billups'); var result = person.get ('fullName' ); lik (resultat, "toran billups", "fullName var" + resultat);); test ('fullName eiendomsoppdateringer når førstnavn er endret', funksjon () var person = App.Person.create (firstName: 'toran', lastName: 'billups'); var result = person.get ('fullName' ), lik (resultat, "toran billups", "fullName var" + resultat); person.set ('firstName', 'wat'); result = person.get ('fullName'); lik ',' fullName var "+ resultat);); test ('fullName-eiendomsoppdateringer når sistnavn er endret', funksjon () var person = App.Person.create (firstName: 'toran', lastName: 'billups'); var result = person.get ('fullName' ), like (resultat, 'toran billups', "fullName var" + resultat); person.set ('lastName', 'tbozz'); resultat = person.get ('fullName'); lik (resultat, 'toran tbozz ',' fullName var "+ resultat););
Hvis du legger til disse to ekstra tester og kjører alle tre fra kommandolinjen, bør du ha to feil. For å få alle tre tester passerer, endre den beregnede egenskapen for å lytte etter endringer på både fornavn og etternavn. Nå hvis du kjører ./ node_modules / karma / bin / karma start
fra kommandolinjen, bør du ha tre beståttester.
App.Person = Ember.Object.extend (firstName: ", lastName:", fullName: funksjon () var firstName = this.get ('firstName'); var lastName = this.get ('lastName') firstName + "+ lastName; .property ('firstName', 'lastName'));
Nå som vi har en beregnet eiendom på modellen, må vi se på malmen selv fordi vi for øyeblikket ikke bruker det nye fullt navn
eiendom. Tidligere måtte du koble opp alt selv, eller bruke Selen til å bekrefte at malen blir gjengitt riktig. Men med ember-testing kan du nå integrering teste dette ved å legge til noen få linjer med JavaScript og et plugin for Karma.
Åpne først package.json
fil og legg til karma-ember-preprocessoravhengigheten. Etter at du har oppdatert package.json
fil, gjør npm installasjon
fra kommandolinjen for å trekke dette ned.
"avhengigheter": "karma-ember-preprocessor": "*", "karma-qunit": "*", "karma": "0.10.2"
Nå som du har forhåndsbehandleren installert, må vi gjøre Karma oppmerksom på malfiler. I filer
delen av din karma.conf.js
fil legg til følgende for å fortelle Karma om håndteringsmalene.
modul.exports = funksjon (karma) karma.set (basePath: 'js', filer: ["leverandør / jquery / jquery.min.js", "leverandør / styrer / handlebars.js", "leverandør / ember / ember.js "," leverandør / jquery-mockjax / jquery.mockjax.js "," app.js "," tester / *. js "," maler / * .håndtak "], logLevel: karma.LOG_ERROR, nettlesere: ['PhantomJS'], singleRun: true, autoWatch: false, frames: ["qunit"]); ;
Neste må vi fortelle Karma hva du skal gjøre med disse styringsfilene, fordi vi teknisk sett ønsker å ha hver mal prekompilert før den overleveres til PhantomJS. Legg til preprosessorkonfigurasjonen og pek noe med en filtypenavn for * .handlebars
på ember preprocessor. Du må også legge til plugin-konfigurasjonen for å registrere ember-forprosessoren (sammen med noen få andre som vanligvis følger med Karma standardkonfigurasjon).
modul.exports = funksjon (karma) karma.set (basePath: 'js', filer: ["leverandør / jquery / jquery.min.js", "leverandør / styrer / handlebars.js", "leverandør / ember / ember.js "," leverandør / jquery-mockjax / jquery.mockjax.js "," app.js "," tester / *. js "," maler / * .håndtak "], logLevel: karma.LOG_ERROR, nettlesere: ['PhantomJS'], singleRun: true, autoWatch: falsk rammeverk: ["qunit"], plugins: ['karma-qunit', 'karma-krom-launcher', 'karma-ember-preprocessor', 'karma- phantomjs-launcher '], forprosessorer: "** / *. styrer":' ember '); ;
Nå som vi har Karma konfigurasjonsoppsett for integrasjonstesting, legg til en ny fil med navnet integration_tests.js
under tester
mappe. I denne mappen må vi legge til en enkel test for å bevise at vi kan stå opp hele Ember.js-søknaden uten feil. Legg til en enkel qunit test for å se om vi kan treffe '/'
rute og få grunnleggende HTML returnert. For den første testen hevder vi bare at bord
tag eksisterer i HTML som ble generert.
test (hello world), funksjon () App.reset (); besøk ("/"). deretter (funksjon () ok (eksisterer ("tabell"));;;);
Legg merke til at vi bruker noen få hjelpere som er bygget inn i ember-testing som besøk
og finne
. De besøk
Helper er en ember vennlig måte å fortelle søknaden hvilken tilstand som skal være under gjennomføringen. Denne testen starter på '/'
rute fordi det er der folkemodellene blir bundet til malen og vårt HTML-tabell er generert. De finne
hjelper er en rask måte å lete opp elementer i DOM ved hjelp av CSS-selektorer som du ville med jQuery for å bekrefte noe om merkingen.
Før vi kan kjøre denne testen, må vi legge til en testhjelpefil som vil injisere testhjelpene og angi et generisk rotelement. Legg til koden under, til en fil som heter integration_test_helper.js
i samme tester
katalogen. Dette vil sikre at søknaden vår har testhjelpene på utførelsestidspunktet.
document.write (''); App.rootElement = '# ember-testing'; App.setupForTesting (); App.injectTestHelpers (); funksjon eksisterer (selector) return !! find (selector). lengde;
Nå fra kommandolinjen bør du kunne utføre integreringstesten ovenfor. Hvis du har en bestått test, fjerner du bordet fra håndtaksmalen for å gjøre det feil (bare for å bevise at Ember genererte HTML ved hjelp av den aktuelle malen).
Nå som vi har integreringstestoppsettet, er det på tide å skrive den som hevder at vi viser hver bruker fullt navn
i stedet for deres fornavn
. Vi vil først hevde at vi får to rader, en for hver person.
test ("hej verden", funksjon () App.reset (); besøk ("/"). deretter (funksjon () var rader = finn ("tabell tr"). lengde; lik (rader, 2 rader );););
Merk: Programmet returnerer for tiden hardkodede data for å holde alt enkelt for øyeblikket. Hvis du er nysgjerrig på hvorfor vi får to personer, her er det finne
metode på modellen:
App.Person.reopenClass (people: [], find: function () var først = App.Person.create (firstName: 'x', lastName: 'y'); var sist = App.Person.create (firstName: 'x', lastName: 'y'); this.people.pushObject (first); this.people.pushObject (sist); returnere.personer;);
Hvis vi driver testene nå, bør vi fortsatt ha alt som går fordi to personer returneres som vi forventer. Deretter må vi få tabellcellen som viser personens navn og hevder at den bruker fullt navn
eiendom i stedet for bare fornavn
.
test ("hej verden", funksjon () App.reset (); besøk ("/"). deretter (funksjon () var rader = finn ("tabell tr"). lengde; lik (rader, 2 rader ); fullName = "(" tabell tr: eq (0) td: eq (0) "). tekst (); lik (fullName," xy ";" den første tabellraden hadde fullName: "+ fullName); ););
Hvis du kjører testen ovenfor, bør du se en feiltest, fordi vi ennå ikke har oppdatert malen som skal brukes fullt navn
. Nå som vi har en feiltest, oppdaterer du malen som skal brukes fullt navn
og kjør testene med ./ node_modules / karma / bin / karma start
. Du bør nå ha en bestått pakke med begge enheter og integreringstester.
Hvis du spør deg selv, "når skal jeg skrive en unit test vs en integreringstest?", Er svaret rett og slett: Hva vil være mindre smertefullt? Hvis du skriver en enhetstest er raskere og det forklarer problemet bedre enn en mye større integreringstest, så sier jeg skrive enhetsprøven. Hvis enhetstestene virker mindre verdifulle fordi du gjør grunnleggende CRUD, og den virkelige oppførselen er i samspillet mellom komponenter, sier jeg skrive integreringstesten. Fordi integreringstestene som er skrevet med ember-testing, er flammende raskt, er de en del av utviklerens tilbakemeldingssyklus og bør brukes på samme måte som en enhetstest når det er fornuftig.
For å vise en CRUD som integreringstest i aksjon, skriv følgende test for å bevise Legg til knappen setter personen inn i samlingen og at en ny rad blir gjengitt i håndtaksmalen.
test ("legg til legger til en annen person i html-tabellen", funksjon () App.Person.people = []; App.reset (); besøk ("/"). deretter (funksjon () var rader = finn lengde like (rad 2, "tabellen hadde" + rader + "rader"); fillIn (".navn", "foo"); fillIn (".navn", "bar") , return, klikk ("send");). deretter (funksjon () lik (finn ("tabell tr"). lengde, 3, "folketabellen var ikke fullført"); tr: eq (2) td: eq (0) "). tekst ()," foo bar "," fullName for personen var feil ");;;
Begynn med å fortelle testen hvilken stat du vil jobbe med, og bruk deretter Fyll inn
hjelper, legg til fornavn og etternavn. Nå hvis du klikker på sende inn knappen den skal legge til den personen i HTML-tabellen, så i retur deretter
Vi kan hevde at det finnes tre personer i HTML-tabellen. Kjør denne testen, og den skal mislykkes fordi Ember-kontrolleren ikke er fullført.
For å få testen forbi, legg til følgende linje i PeopleController
App.PeopleController = Ember.ArrayController.extend (handlinger: addPerson: function () var person = firstName: this.get ('firstName'), sistnavn: this.get ('lastName'); App.Person .add (person););
Nå hvis du kjører testene med ./ node_modules / karma / bin / karma start
Det skal vise tre personer i gjengitt HTML.
Den siste testen er slettet, legg merke til at vi finner knappen for en bestemt rad, og klikk på den. I de neste deretter
Vi kontrollerer bare at en mindre person er vist i HTML-tabellen.
test ("slette vil fjerne personen for en gitt rad", funksjon () App.Person.people = []; App.reset (); besøk ("/"). deretter (funksjon () var rader = finn ("tabell"), lengde, lik (rad, 2, "tabellen hadde" + rader + "rader"); lengde 1, "bordet av mennesker var ikke fullført);;")))
For å få dette passerer, legger du bare til følgende linje til PeopleController
:
App.PeopleController = Ember.ArrayController.extend (handlinger: addPerson: function () var person = firstName: this.get ('firstName'), sistnavn: this.get ('lastName'); App.Person .add (person);, deletePerson: funksjon (person) App.Person.remove (person););
Kjør testene fra kommandolinjen, og du bør nok en gang bestå en prøvepakke.
Så det bryter opp vår prøveapplikasjon. Ta gjerne spørsmål på ned i kommentarene.
Hvis du foretrekker å bruke Grunt i stedet for karma-ember-preprosessoren, fjerner du bare pluginene og preprosessors konfigurasjon. Fjern også maler / *. styret
fra filseksjonen som Karma trenger ikke å forkompilere malene. Her er en forenklet karma.conf.js
Det fungerer når du bruker grunt til å forkompilere styreskjermene.
module.exports = funksjon (karma) karma.set (basePath: 'js', filer: ["lib / deps.min.js", // bygget av din grunne oppgave "tester / *. js"), logLevel : karma.LOG_ERROR, nettlesere: ['PhantomJS'], singleRun: true, autoWatch: false, frames: ["qunit"]); ;
Og det er det!