Velkommen til denne serien om å utvikle Laravel-applikasjoner ved hjelp av en adferdsdrevet utvikling (BDD) tilnærming. Full Stack BDD kan virke komplisert og skremmende. Det er like mange måter å gjøre det på som det er utviklere.
I denne serien vil jeg gå deg gjennom tilnærmingen min med å bruke Behat og PhpSpec til å designe en Laravel-applikasjon fra grunnen av.
Det er mange ressurser på BDD generelt, men Laravel-spesifikt materiale er vanskelig å finne. Derfor vil vi i denne serien fokusere mer på Laravel-relaterte aspekter og mindre på de generelle tingene som du kan lese om mange andre steder.
Når vi beskriver adferd, som også kalles for å skrive historier og spesifikasjoner, vil vi bruke en utenforliggende tilnærming. Dette betyr at hver gang vi bygger en ny funksjon, begynner vi å skrive den generelle brukerhistorien. Dette er normalt fra klientene eller interessentperspektivet.
Hva forventer vi å skje når vi gjør dette?
Vi har ikke lov til å skrive noen kode før vi har et sviktende, rødt steg for eksempel, med mindre vi refactoring eksisterende kode.
Noen ganger vil det være nødvendig å løse iterativt en liten del av en historie eller funksjon (to ord som jeg bruker om hverandre) som vi jobber på. Dette vil ofte bety å skrive spesifikasjoner med PhpSpec. Noen ganger vil det ta mange iterasjoner på et integrasjons- eller enhetsnivå før hele historien (på et akseptnivå) går forbi. Alt dette høres veldig komplisert, men det er egentlig ikke. Jeg er en stor tro på å lære ved å gjøre, så jeg tror at alt vil gjøre mer fornuftig når vi begynner å skrive noen faktisk kode.
Vi skal skrive historier og spesifikasjoner på fire forskjellige nivåer:
Mesteparten av tiden fungerer vår funksjonelle suite som vårt akseptelag. Måten vi vil beskrive våre funksjoner i vår funksjonelle suite, vil ligner på hvordan vi vil skrive aksepthistorier (ved hjelp av en automatisert nettleseramme) og vil som sådan skape mye duplisering.
Så lenge historiene beskriver oppførselen fra kundens synspunkt, tjener de som aksepthistorier. Vi vil bruke Symfony DomCrawler til å teste utdataene fra vår søknad. Senere i serien kan det hende at vi må teste gjennom en faktisk nettleser som også kan kjøre JavaScript. Testing gjennom nettleseren legger til noen nye bekymringer, siden vi må sørge for at vi laster timetestmiljøet når suiten kjøres.
I vår funksjonelle suite har vi tilgang til Laravel-applikasjonen, som er veldig praktisk. Først av alt gjør det det enkelt å skille mellom miljøer. For det andre, ikke å gå gjennom en nettleser, gjør vår testpakke mye raskere. Når vi vil implementere en ny funksjon, vil vi skrive en historie i vår funksjonelle suite ved hjelp av Behat.
Vår integrasjonspakke vil teste oppførselen til kjernen av applikasjonen vår, som ikke nødvendigvis trenger tilgang til Laravel. Integrasjonspakken vil normalt være en blanding av Behat-historier og PhpSpec-spesifikasjoner.
Våre enhetstester vil bli skrevet i PhpSpec og vil teste isolerte små enheter av applikasjonskjernen. Våre enheter, verdiobjekter etc. har alle spesifikasjoner.
Gjennom hele denne serien, med utgangspunkt i neste artikkel, vil vi bygge et system for sporingstid. Vi starter med å beskrive atferd fra utsiden ved å skrive Behat-funksjoner. Den interne oppførselen til søknaden vår vil bli beskrevet ved hjelp av PhpSpec.
Sammen vil disse to verktøyene hjelpe oss med å føle oss komfortable med kvaliteten på applikasjonen vi bygger. Vi vil primært skrive funksjoner og spesifikasjoner på tre nivåer:
I vår funksjonelle pakke vil vi krype HTTP-responsene i applikasjonen vår i en hodeløs modus, noe som betyr at vi ikke vil gå gjennom nettleseren. Dette vil gjøre det lettere å samhandle med Laravel og gjøre vår funksjonelle suite tjene som vårt akseptelag også.
Senere, hvis vi ender med å ha et mer komplisert brukergrensesnitt, og det kan hende at vi må teste noen JavaScript, kan vi også legge til en dedikert godkjenningssoalett. Denne serien er fortsatt i arbeid, så vær så snill å slippe forslagene dine i kommentarfeltet.
Legg merke til at for denne opplæringen antar jeg at du har en fersk installasjon av Laravel (4.2) oppe. Fortrinnsvis bruker du Laravel Homestead, som er det jeg brukte da jeg skrev denne koden.
Før vi begynner med noe virkelig arbeid, la oss sørge for at vi har Behat og PhpSpec oppe og løpende. Først skjønt, liker jeg å gjøre litt rengjøring når jeg starter et nytt laravelprosjekt og slett ting jeg ikke trenger:
git rm -r app / tester / phpunit.xml CONTRIBUTING.md
Hvis du sletter disse filene, må du sørge for at du oppdaterer composer.json
arkiver deretter:
"autoload": "klassekart": ["app / kommandoer", "app / kontroller", "app / modeller", "app / database / migrasjoner", "app / database / frø"],
Og selvfølgelig:
$ komponent dump-autoload
Nå er vi klare til å trekke inn BDD-verktøyene vi trenger. Bare legg til en require-dev
delen til din composer.json
:
"required": "behat / behat": "~ 3.0", "phpspec / phpspec": "~ 2.0", "phpunit / phpunit ":" ~ 4,1 ",
"Hvorfor drar vi i PHPUnit?" kan du tenke? Vi kommer ikke til å skrive gode ol 'PHPUnit test tilfeller i denne serien, men påstandene er et praktisk verktøy sammen med Behat. Vi vil se det senere i denne artikkelen når vi skriver vår første funksjon.
Husk å oppdatere dine avhengigheter etter endring composer.json
:
$ komponent oppdatering --dev
Vi er nesten ferdige med å installere og sette opp ting. PhpSpec fungerer ut av esken:
$ leverandør / bin / phpspec kjøre 0 spesifikasjoner 0 eksempler 0ms
Men Behat trenger å gjøre en rask løp med --i det
alternativ for å sette alt opp:
$ vendor / bin / behat --init + d funksjoner - plasser dine * .feature filer her + d funksjoner / bootstrap - plasser kontekst klassene dine her + f features / bootstrap / FeatureContext.php - plasser definisjoner, transformasjoner og kroker her $ leverandør / bin / behat Ingen scenarier Ingen trinn 0m0.14s (12.18Mb)
Den første kommandoen skapt et skinnende nytt FeatureContext
klasse, der vi kan skrive de trinndefinisjonene som trengs for funksjonene våre:
Skriver vår første funksjon
Vår første funksjon vil være veldig enkel: Vi vil ganske enkelt sørge for at vår nye Laravel installasjon hilser oss med "du er kommet." på hjemmesiden. Jeg legger meg inn litt dumt
gitt
gå også,Gitt jeg er logget inn
, som bare tjener til å vise hvor lett samspill med Laravel i våre funksjoner er.Teknisk vil jeg kategorisere denne typen funksjon som en funksjonell test, siden den samhandler med rammen, men det tjener også som en aksepttest, siden vi ikke ville se noen andre resultater fra å kjøre en lignende test gjennom et nettleserprøveverktøy. For nå vil vi holde fast i vår funksjonelle test suite.
Gå videre og opprett en
welcome.feature
filen og legg den innfunksjoner / funksjonell
:# features / functional / welcome.feature Feature: Innbydende utvikler Som Laravel-utvikler For å kunne begynne et nytt prosjekt må jeg bli møtt ved ankomst Scenario: Hilsenutvikler på hjemmesiden Gitt Jeg er innlogget Når jeg besøker "/" så jeg bør se "du er kommet."Ved å sette funksjonelle funksjoner i a
funksjonell
katalog, det blir lettere for oss å administrere våre suiter senere. Vi ønsker ikke integreringstypefunksjoner som ikke krever at Laravel må vente på den sakte funksjonelle pakken.Jeg liker å holde ting rent og pent, så jeg tror vi burde ha en dedikert funksjonskontekst for vår funksjonelle suite som kan gi oss tilgang til Laravel. Du kan bare gå videre og kopiere eksisterende
FeatureContext
fil og endre klassenavnet tilLaravelFeatureContext
. For at dette skal fungere, trenger vi også enbehat.yml
konfigurasjonsfil.Opprett en i rotkatalogen av prosjektet ditt og legg til følgende:
standard: suiter: funksjonelle: stier: [% paths.base% / features / functional] sammenhenger: [LaravelFeatureContext]Jeg tror YAML her er ganske selvforklarende. Vår funksjonelle suite vil se etter funksjoner i
funksjonell
katalog og kjør dem gjennomLaravelFeatureContext
.Hvis vi prøver å kjøre Behat på dette punktet, vil det fortelle oss å implementere de nødvendige trinndefinisjonene. Vi kan ha Behat legge til de tomme stillasemetodene til
LaravelFeatureContext
med følgende kommando:$ vendor / bin / behat -dry-run --append-snippets $ vendor / bin / behat Funksjon: Innbydende utvikler Som Laravel-utvikler For å kunne begynne et nytt prosjekt, må jeg bli møtt etter arival Scenario: Hilsen utvikler på Hjemmeside # funksjoner / funksjonell / velkommen.featur: 6 Gitt jeg er innlogget # LaravelFeatureContext :: iAmLoggedIn () TODO: skriv ventende definisjon Når jeg besøker "/" # LaravelFeatureContext :: iVisit () Så skal jeg se "Du er kommet. " # LaravelFeatureContext :: iShouldSee () 1 scenario (1 venter) 3 trinn (1 venter, 2 hoppet over) 0m0.28s (12.53Mb)Og nå, som du ser fra produksjonen, er vi klare til å begynne å implementere det første av trinnene våre:
Gitt jeg er logget inn
.PHPUnit test saken som sendes med Laravel lar oss gjøre ting som
$ Dette-> være ($ bruker)
, som logger inn i en gitt bruker. Til slutt ønsker vi å kunne samhandle med Laravel som om vi brukte PHPUnit, så la oss gå videre og skrive trinndefinisjonskoden "vi skulle ønske vi hadde":/ ** * @Given Jeg er logget inn * / offentlig funksjon iAmLoggedIn () $ user = new User; $ Dette-> være ($ bruker);Dette vil ikke fungere selvfølgelig, siden Behat har ingen anelse om Laravel-spesifikke ting, men jeg vil vise deg på et øyeblikk hvor lett det er å få Behat og Laravel til å leke pent sammen.
Hvis du tar en titt i Laravel kilden og finner
Belyse \ Foundation \ Testing \ Testcase
klassen, som er klassen som standard test saken strekker seg fra, vil du se at starter fra Laravel 4.2, har alt blitt flyttet til et trekk. DeApplicationTrait
er nå ansvarlig for oppstart av enapplikasjon
eksempel, sette opp en HTTP-klient og gi oss noen hjelpemetoder, for eksempelvære()
.Dette er ganske kult, hovedsakelig fordi det betyr at vi bare kan trekke den inn i våre Behat-sammenhenger med nesten ingen oppsett påkrevd. Vi har også tilgang til
AssertionsTrait
, men dette er fortsatt knyttet til PHPUnit.Når vi trekker inn egenskapen, må vi gjøre to ting. Vi må ha en
SETUP ()
metode, som den iBelyse \ Foundation \ Testing \ Testcase
klasse, og vi trenger encreateApplication ()
metode, som den i standard Laravel test saken. Egentlig kan vi bare kopiere disse to metodene og bruke dem direkte.Det er bare en ting å legge merke til: I PHPUnit, metoden
SETUP ()
vil automatisk bli kalt før hver test. For å oppnå det samme i Behat, kan vi bruke@BeforeScenario
merknad.Legg til følgende i din
LaravelFeatureContext
:bruk Illuminate \ Foundation \ Testing \ ApplicationTrait; / ** * Denne kontekstklasse. * / klasse LaravelFeatureContext implementerer SnippetAcceptingContext / ** * Ansvarlig for å levere en Laravel app instans. * / bruk ApplicationTrait; / ** * Initialiserer kontekst. * * Hvert scenario får sin egen kontekstobjekt. * Du kan også sende vilkårlige argumenter til kontekstkonstruktøren gjennom behat.yml. * / offentlig funksjon __construct () / ** * @BeforeScenario * / public function setUp () if (! $ this-> app) $ this-> refreshApplication (); / ** * Oppretter applikasjonen. * * @return \ Symfony \ Component \ HttpKernel \ HttpKernelInterface * / offentlig funksjon createApplication () $ unitTesting = true; $ testEnvironment = 'testing'; retur krever __DIR __. '/ ... / ... /bootstrap/start.php';Ganske enkelt, og se hva vi får når vi løper Behat:
$ vendor / bin / behat Funksjon: Innbydende utvikler Som Laravel-utvikler For å kunne begynne et nytt prosjekt, må jeg bli møtt etter arival Scenario: Hilsenutvikler på hjemmesiden # funksjoner / funksjonell / velkommen.featur: 6 Gitt jeg er logget inn # LaravelFeatureContext :: iAmLoggedIn () Når jeg besøker "/" # LaravelFeatureContext :: iVisit () TODO: skriv ventende definisjon Da skal jeg se "Du er kommet." # LaravelFeatureContext :: iShouldSee () 1 scenario (1 ventende) 3 trinn (1 bestått, 1 ventet, 1 hoppet over) 0m0.73s (17.92Mb)Et grønt første skritt, noe som betyr at oppsettet vårt fungerer!
Deretter kan vi implementere
Når jeg besøker
skritt. Denne er super enkel, og vi kan bare brukeanrop()
metode somApplicationTrait
gir. En linje med kode vil få oss der:/ ** * @Når jeg besøker: uri * / offentlig funksjon iVisit ($ uri) $ this-> call ('GET', $ uri);Det siste trinnet,
Da skal jeg se
, tar litt mer og vi må trekke inn to avhengigheter. Vi trenger PHPUnit for påstanden, og vi vil trenge Symfony DomCrawler å søke etter "du er kommet." tekst.Vi kan implementere det slik:
bruk PHPUnit_Framework_Assert som PHPUnit; bruk Symfony \ Component \ DomCrawler \ Crawler; ... / ** * @Then bør jeg se: tekst * / offentlig funksjon iShouldSee ($ tekst) $ crawler = ny Crawler ($ this-> client-> getResponse () -> getContent ()); PHPUnit :: assertCount (1, $ crawler-> filterXpath ("// text () [. = '$ Text']"));Dette er ganske mye den samme koden som du ville skrive hvis du brukte PHPUnit. De
filterXpath ()
del er litt forvirrende, og vi vil ikke bekymre oss om det nå, siden det er litt utenfor omfanget av denne artikkelen. Bare stol på meg at det fungerer.Kjører Hvor en siste gang er gode nyheter:
$ vendor / bin / behat Funksjon: Innbydende utvikler Som Laravel-utvikler For å kunne begynne et nytt prosjekt, må jeg bli møtt etter arival Scenario: Hilsenutvikler på hjemmesiden # funksjoner / funksjonell / velkommen.featur: 6 Gitt jeg er logget inn # LaravelFeatureContext :: iAmLoggedIn () Når jeg besøker "/" # LaravelFeatureContext :: iVisit () Så skal jeg se "Du er kommet." # LaravelFeatureContext :: iShouldSee () 1 scenario (1 bestått) 3 trinn (3 passert) 0m0.82s (19.46Mb)Funksjonen fungerer som forventet og utvikleren blir møtt ved ankomst.
Konklusjon
Den komplette
LaravelFeatureContext
bør nå se ut som dette:app) $ this-> refreshApplication (); / ** * Oppretter applikasjonen. * * @return \ Symfony \ Component \ HttpKernel \ HttpKernelInterface * / offentlig funksjon createApplication () $ unitTesting = true; $ testEnvironment = 'testing'; retur krever __DIR __. '/ ... / ... /bootstrap/start.php'; / ** * @Given Jeg er logget inn * / offentlig funksjon iAmLoggedIn () $ user = new User; $ Dette-> være ($ bruker); / ** * @Når jeg besøker: uri * / offentlig funksjon iVisit ($ uri) $ this-> call ('GET', $ uri); / ** * @Then skal jeg se: tekst * / offentlig funksjon iShouldSee ($ tekst) $ crawler = ny Crawler ($ this-> client-> getResponse () -> getContent ()); PHPUnit :: assertCount (1, $ crawler-> filterXpath ("// text () [. = '$ Text']"));Vi har nå et veldig fint fundament å bygge videre på når vi fortsetter å utvikle vårt nye Laravel-program ved hjelp av BDD. Jeg håper jeg har vist deg hvor lett det er å få Laravel og Behat å leke pent sammen.
Vi har tatt på mange forskjellige temaer i denne første artikkelen. Du trenger ikke å bekymre deg, vi vil ta en mer grundig titt på alt ettersom serien fortsetter. Hvis du har spørsmål eller forslag, vennligst legg igjen en kommentar.