Un flux de lucru BDD cu Behat și Phpspec

În acest tutorial, vom analiza două instrumente BDD diferite, Behat și phpspec și vom vedea cum vă pot ajuta în procesul de dezvoltare. Învățarea BDD poate fi confuză. Noua metodologie, noi instrumente și multe întrebări, precum "ce să testez?" și "ce instrumente să folosim?". Sper că acest exemplu destul de simplu vă va oferi idei despre modul în care puteți integra BDD în propriul flux de lucru.

Inspirația mea

M-am inspirat să scriu acest tutorial de către Taylor Otwell, creatorul cadrului Laravel. De câteva ori, l-am auzit pe Taylor explicând de ce nu face mai mult TDD / BDD spunând că îi place să planifice mai întâi API-ul codului său, înainte de a începe efectiv să o pună în aplicare. Am auzit acest lucru de la mulți dezvoltatori și de fiecare dată când mă gândesc la mine: "Dar acesta este cazul perfect pentru TDD / BDD!". Taylor spune că îi place să-și elaboreze API-ul codului său, scriind codul pe care dorea să-l aibă. El va începe apoi să codifice și nu va fi satisfăcut până când nu va obține acel API exact. Argumentul are sens dacă testați / examinați doar la nivel de unitate, dar folosind un instrument ca Behat, începeți cu comportamentul extern al software-ului dvs., care este, în principiu, în măsura în care înțeleg, ceea ce Taylor dorește să realizeze.

Ce vom acoperi

În acest tutorial, vom construi o clasă simplă de încărcare a fișierelor de configurare. Vom începe prin folosirea abordării lui Taylor și apoi trecerea la o abordare BDD în schimb. Exemplele sunt minimaliste, dar totuși vom fi nevoiți să ne facem griji cu privire la programări, metode statice etc., deci toate în toate, cred că ar trebui să fie suficiente pentru a arăta cum se pot completa Behat și phpspec.

Disclaimer: În primul rând, acest articol nu este a Noțiuni de bază ghid. Acesta presupune cunoștințe de bază despre BDD, Behat și phpspec. Probabil că ați analizat deja aceste instrumente, dar încă vă luptați cu modul în care să le folosiți efectiv în fluxul zilnic de lucru. Dacă doriți să vă spălați pe phpspec, aruncați o privire la tutorialul meu de început. În al doilea rând, folosesc Taylor Otwell ca exemplu. Nu stiu nimic despre felul in care lucreaza Taylor, pe langa ceea ce l-am auzit spunandu-l in podcast-uri etc. Imi folosesc exemplul pentru ca este un dezvoltator minunat (a facut-o pe Laravel!) Si pentru ca este bine cunoscut. S-ar putea să fi folosit altcineva, deoarece majoritatea dezvoltatorilor, inclusiv mine, nu fac tot timpul BDD. De asemenea, nu spun că fluxul de lucru pe care Taylor îl descrie este rău. Cred că este o idee strălucitoare de a pune niște gânduri în codul tău înainte să-l scriu. Acest tutorial este menit să arate modul BDD de a face acest lucru.

Fluxul de lucru al lui Taylor

Să începem să aruncăm o privire asupra modului în care Taylor ar putea să proiecteze acest încărcător de fișiere de configurare. Taylor spune că îi place să ardă doar un fișier text gol în editorul său și apoi să scrie cum ar dori dezvoltatorii să poată interacționa cu codul său (API). Într-un context BDD, aceasta este în mod normal menționată ca testarea comportamentului extern al software-ului și instrumente precum Behat sunt excelente pentru acest lucru. Vom vedea asta într-un timp scurt.

În primul rând, poate Taylor va lua o decizie cu privire la fișierele de configurare. Cum ar trebui să funcționeze? La fel ca în Laravel, să folosim doar retele simple de PHP. Un exemplu de fișier de configurare ar putea arăta astfel:

# config.php  'UTC', );

În continuare, cum ar trebui să funcționeze codul care folosește acest fișier de configurare? Să facem acest lucru prin modul Taylor și să scriem codul pe care l-am dorit să îl avem:

$ config = Config :: încărcare ('config.php'); $ Configura cam> get ( 'fus orar'); // returnează 'UTC' $ config-> get ('timezone', 'CET'); // returnează 'CET' dacă 'timezone' nu este configurat $ config-> set ('timezone', 'GMT'); $ Configura cam> get ( 'fus orar'); // returnează "GMT" 

Bine, deci arata destul de bine. Mai întâi avem un apel static către un a sarcină() funcție, urmată de trei cazuri de utilizare: 

  1. Obținerea "fusului orar" din fișierul de configurare. 
  2. Obținerea unei valori implicite, dacă "fusul orar" nu este încă configurat. 
  3. Schimbarea unei opțiuni de configurare prin cadru la altceva. Vom descrie fiecare dintre aceste cazuri de utilizare sau scenarii, cu Behat într-un timp scurt.

Are sens să folosești Behat pentru astfel de lucruri. Behat nu ne va forța să luăm decizii de proiectare - pentru asta avem phpspec. Vom muta pur și simplu cerințele, pe care tocmai le-am descris, într-un Behat caracteristică pentru a ne asigura că avem dreptate, când începem să construim. Caracteristica noastră va servi ca un test de acceptare a cerințelor noastre de a vorbi astfel.

Dacă vă uitați la codul pe care l-am scris, un alt motiv pentru a utiliza Behat, în loc de numai phpspec, este apelul static. Nu este ușor să testați metodele statice, mai ales dacă nu utilizați doar un instrument ca phpspec. Vom vedea cum putem face acest lucru atunci când avem atât Behat cât și phpspec disponibile.

Înființat

Presupunând că utilizați compozitor, configurarea Behat și phspec este un proces foarte simplu, în două etape.

În primul rând, aveți nevoie de o bază composer.json fişier. Aceasta include Behat și phpspec și utilizează psr-4 pentru a autoload clasele:

"necesită-dev": "behat / behat": "~ 3.0", "phpspec / phpspec": "~ 2.0"  

Alerga compozitorul instala pentru a prelua dependențele.

phpspec nu are nevoie de nici o configurație pentru a rula, în timp ce Behat are nevoie de tine pentru a rula următoarea comandă pentru a genera un schelet de bază:

$ furnizor / bin / behat - init

Asta e tot ce este necesar. Aceasta nu poate fi o scuză pentru faptul că nu faceți BDD!

Planificarea caracteristicilor cu Behat

Deci, acum că suntem cu toții pregătiți, suntem gata să începem să facem BDD. Deoarece face BDD înseamnă instalarea și utilizarea Behat și phpspec, dreapta?

În ceea ce mă privește, am început deja să facem BDD. Am descris în mod eficient comportamentul extern al software-ului nostru. "Clienții" noștri din acest exemplu sunt dezvoltatori care vor interacționa cu codul nostru. Prin "în mod eficient", vreau să spun că am descris comportamentul într-un mod pe care îl vor înțelege. Am putea să luăm codul pe care l-am prezentat deja, să-l punem într-un fișier README și fiecare dezvoltator demn de PHP ar înțelege utilizarea acestuia. Deci, acest lucru este destul de bun de fapt, dar am două lucruri importante pe care să le notez în acest sens. Mai întâi, descrierea comportamentului software-ului care utilizează codul funcționează numai în acest exemplu deoarece "clienții" sunt programatori. În mod normal, testez ceva care va fi folosit de oamenii "normali". O limbă umană este mai bună decât PHP când vrem să comunicăm cu oamenii. În al doilea rând, de ce nu automatizați acest lucru? Nu voi argumenta de ce ar putea fi o idee bună.

Acestea fiind spuse, cred ca incepand sa folosesc Behat acum ar fi o decizie rezonabila.

Folosind Behat, dorim să descriem fiecare dintre scenariile pe care le-am prezentat mai sus. Nu vrem să acoperim pe scară largă fiecare caz de margine implicat în utilizarea software-ului. Dispunem de phpspec dacă acest lucru ar fi necesar pentru a repara bug-uri de-a lungul drumului etc. Cred că mulți dezvoltatori, poate inclusiv Taylor, simt că trebuie să gândească totul și să decidă totul înainte de a putea scrie teste și specificații. De aceea, ei aleg să înceapă fără BDD, pentru că nu vor să decidă totul în prealabil. Nu este cazul lui Behat, deoarece descriem comportamentul și folosirea externă. Pentru a folosi Behat pentru a descrie o caracteristică, nu trebuie să decidem nimic mai mult decât în ​​exemplul de mai sus, folosind un fișier text brut. Trebuie doar să definim cerințele funcției - în acest caz API-ul extern al clasei de încărcare a fișierelor de configurare.

Acum, să luăm codul PHP de mai sus și să îl transformăm într-o caracteristică Behat, folosind limba engleză (de fapt, folosind limba Gherkin).

Faceți un fișier în caracteristici/ director, numit config.feature, și completați următoarele scenarii:

Caracteristică: Fișiere de configurare Pentru a-mi configura aplicația Ca dezvoltator trebuie să pot stoca opțiunile de configurare într-un fișier Scenariu: Obținerea unei opțiuni configurate Având în vedere că există un fișier de configurare Și opțiunea 'fus orar' este configurată la 'UTC' Incarc fisierul de configurare Apoi, ar trebui sa primesc optiunea 'UTC' ca 'fus orar' Scenariu: Obtinerea unei optiuni neconfigurate cu o valoare implicita Avand in vedere ca exista un fisier de configurare si optiunea 'fusul orar' nu este configurata inca. Fișierul Apoi trebuie să obțineți valoarea implicită 'CET' ca opțiune 'fus orar' Scenariu: Setarea unei opțiuni de configurare Dat fiind că există un fișier de configurare Și opțiunea 'fusul orar' este configurată la 'UTC' Când încărc fișierul de configurare Și am setat ' opțiunea de configurare a "zonei de fus orar" la "GMT" Atunci ar trebui să primesc "GMT" ca opțiune "fus orar" 

În această caracteristică, descriem din exterior modul în care "un dezvoltator" ar putea să stocheze opțiunile de configurare. Nu ne pasă de comportamentul intern - atunci când vom începe să folosim phpspec. Atâta timp cât această caracteristică funcționează verde, nu ne pasă ce se întâmplă în spatele scenei.

Să vedem Behat și să vedem ce crede despre caracteristica noastră:

$ vendor / bin / behat - dry-run - fișiere de tip "append" 

Cu această comandă, îi spunem lui Behat să adauge definițiile pasului necesar în contextul nostru de funcții. Nu voi merge prea mult în detaliu despre Behat, dar asta adaugă o mulțime de metode goale pentru noi FeatureContext clasă care să corespundă pașilor noștri de mai sus.

De exemplu, aruncați o privire la definiția pasului pe care Behat a adăugat-o pentru există un fișier de configurare pas pe care îl folosim ca pas "dat" în toate cele trei scenarii:

/ ** * @Deoarece există un fișier de configurare * / funcția publică thereIsAConfigurationFile () throw new PendingException ();  

Acum, tot ce trebuie să faceți este să completați un cod pentru a descrie acest lucru.

Definirea pasului de scriere

Înainte de a începe, am două puncte importante de făcut despre definițiile pasului:

  1. Ideea este de a dovedi că comportamentul acum nu este așa cum vrem să fie. După aceea, putem începe să proiectăm codul nostru, de cele mai multe ori folosind phpspec, pentru a ajunge la verde.
  2. Punerea în aplicare a definițiilor pasului nu este importantă - avem nevoie doar de ceva care funcționează și realizează "1". Putem refactor mai târziu.

Dacă alergi furnizor / bin / behat, veți vedea că toate scenariile au acum pași în așteptare.

Începem cu primul pas Dat fiind că există un fișier de configurare. Vom folosi un fișier din fișierul de configurare, astfel încât să putem folosi staticul sarcină() mai târziu. Ne pasă de static sarcină() deoarece ne dă un API frumos Config :: sarcină (), la fel ca fațadele Laravel. Acest pas ar putea fi implementat în numeroase moduri. Pentru moment, cred că ar trebui să ne asigurăm că avem un dispozitiv disponibil și că acesta conține o matrice:

/ ** * @Deoarece există un fișier de configurare * / funcția publică thereIsAConfigurationFile () if (! File_exists ('fixtures / config.php')) arunca o nouă Excepție ("File fixtures / config.php nu a fost găsit") ; $ config = include 'fixtures / config.php'; dacă (! is_array ($ config)) aruncați o nouă excepție ("Fișierele fișiere / config.php ar trebui să conțină o matrice");  

Vom merge la verde cu acest pas fără a implementa un cod în afară de a face acest lucru. Scopul a Dat pas este de a pune sistemul într-o stare cunoscută. În acest caz, asta înseamnă că avem un fișier de configurare.

Pentru a ajunge la primul nostru pas greu, trebuie doar să creați dispozitivul:

# fixtures / config.php 

Apoi, avem un Și pas, care în acest caz este doar un alias pentru Dat. Vrem să vă asigurați că fișierul de configurare conține o opțiune pentru fusul orar. Din nou, acest lucru este legat doar de fixarea noastră, așa că nu ne interesează prea mult. Am lovit codul următor (hackish) împreună pentru a realiza acest lucru:

/ ** * @Pentru opțiunea: opțiunea este configurată pentru: valoarea * / funcția publică theOptionIsConfiguredTo ($ opțiune, valoare $) $ config = include 'fixtures / config.php'; dacă (! is_array ($ config)) $ config = []; $ config [$ opțiune] = valoarea $; $ content = "

Codul de mai sus nu este frumos, dar realizează ceea ce are nevoie. Ne permite să manipulăm dispozitivul nostru din elementul nostru. Dacă rulați Behat, veți vedea că a adăugat opțiunea "fus orar" la config.php prindere:

 'UTC', ); 

Acum este momentul să aduci în original codul Taylor! Pasul Când încărc fișierul de configurare va consta din codul pe care-l interesează de fapt. Vom aduce unele coduri din fișierul text brut de mai devreme și asigurați-vă că rulează:

/ ** * @ Când încărc fișierul de configurare * / funcția publică iLoadTheConfigurationFile () $ this-> config = Config :: load ('fișiere / config.php'); // Taylor! 

Rularea Behat, desigur, acest lucru va eșua, deoarece config nu există încă. Să aducem phpspec la salvare!

Proiectarea cu Phpspec

Când conducem Behat, vom avea o eroare fatală:

Eroare fatală eroare: Clasa "Config" nu a fost găsită ... 

Din fericire, avem disponibil phpspec, inclusiv generatoarele de coduri minunate:

$ vendor / bin / phpspec desc "Config" Specificație pentru Config creată în ... /spec/ConfigSpec.php. $ vendor / bin / phpspec run --format = pretty Vrei să creez "Config" pentru tine? y $ vendor / bin / phpspec rula --format = destul de Config 10 ✔ este inițializabil 1 specificații 1 exemplar (1 trecut) 7ms 

Cu aceste comenzi, phpspec a creat următoarele două fișiere pentru noi:

spec / '- ConfigSpec.php src /' - Config.php

Acest lucru ne-a scăpat de prima eroare fatală, dar Behat încă nu funcționează:

PHP Eroare fatală: Apel la metoda nedefinită Config :: load () în ... 

sarcină() va fi o metodă statică și, ca atare, nu este ușor de specificat cu phpspec. Din două motive, este OK:

  1. Comportamentul sarcină() metoda va fi foarte simplă. Dacă avem nevoie de mai multă complexitate mai târziu, putem extrage logica în metodele mici testabile.
  2. Comportamentul, ca și acum, este acoperit destul de bine de Behat. Dacă metoda nu încarcă fișierul într-un tablou corect, Behat se va scuipa la noi.

Aceasta este una dintre acele situații în care o mulțime de dezvoltatori vor lovi peretele. Ei vor arunca departe phpspec și concluzionează că e de rahat și că lucrează împotriva lor. Dar, a se vedea cât de bine se completează Behat și phpspec reciproc aici?

În loc să încercați să obțineți o acoperire de 100% cu phpspec, permiteți-ne să implementăm un simplu sarcină() funcția și să fie încrezător că este acoperit de Behat:

setări = array ();  încărcarea funcției publice statice (calea $) $ config = new static (); dacă (file_exists ($ path)) $ config-> settings = include $ path; return $ config;  

Suntem destul de siguri că opțiunile de configurare sunt acum încărcate. Dacă nu, restul pașilor noștri vor eșua și putem examina din nou acest lucru.

Construirea caracteristicii cu iterare

Înapoi la verde, cu atât Behat cât și phpspec, ne putem uita acum la următorul nostru pas Apoi ar trebui să primesc "UTC" ca opțiune "fus orar".

/ ** * @Apoi să primesc: valoarea ca: opțiunea opțiune * / funcția publică iShouldGetAsOption ($ valoare, $ opțiune) $ actual = $ this-> config-> get (opțiunea $); // Taylor! dacă (! strcmp ($ value, $ actual) == 0) aruncați o nouă excepție ("Expected $ actual pentru a fi" $ option ".);  

În acest pas, scriem mai mult din codul pe care îl dorim. Dacă alergăm pe Behat, vom vedea că nu avem a obține() metoda disponibilă:

PHP Eroare fatală: Apel la metoda nedefinită Config :: get () în ... 

Este timpul să vă întoarceți la phpspec și să sortați acest lucru.

Testarea accesoriilor și mutatorilor, AKA getters și setters, este aproape ca acel pui vechi sau ou dillemma. Cum putem testa obține() dacă nu avem încă a stabilit() și viceversa. Modul în care am tendința de a face acest lucru este să le testez pe amândouă. Aceasta înseamnă că de fapt vom implementa funcționalitatea pentru a seta o opțiune de configurare, chiar dacă nu am ajuns încă la acest scenariu.

Următorul exemplu ar trebui să facă:

funcția it_gets_and_sets_a_configuration_option () $ this-> get ('foo') -> shouldReturn (null); $ this-> set ('foo', 'bar'); $ This-> get ( 'foo') -> shouldReturn ( 'bar');  

În primul rând, vom avea generatoarele phpspec ne ajuta să începem:

$ vendor / bin / phpspec run --format = pretty Vrei să creez 'Config :: get ()' pentru tine? y $ vendor / bin / phpspec run --format = pretty Vrei să creez 'Config :: set ()' pentru tine? y $ vendor / bin / phpspec run --format = destul de config 10 ✔ este inițializabil 15 ✘ obține și stabilește o opțiune de configurare așteptată "bar", dar a ajuns null ... 1 specs 2 exemple (1 trecut, 1 nu a reușit) 9ms 

Acum, să ne întoarcem la verde:

funcția publică obține (opțiunea $) if (! isset ($ this-> settings [$ option])) return null; returneaza $ this-> settings [$ option];  set de funcții publice ($ opțiune, valoare $) $ this-> setări [$ opțiune] = $ valoare;  

Și, acolo mergem:

$ vendor / bin / phpspec executa --format = destul de Config 10 ✔ este initializabil 15 ✔ primeste si stabileste o optiune de configurare 1 specificatii 2 exemple (2 trecute) 9ms 

Asta ne-a făcut mult. Fugind pe Behat, vedem că acum suntem în cel de-al doilea scenariu. Apoi, trebuie să implementăm opțiunea implicită, deoarece obține() tocmai se întoarce nul chiar acum.

Primul pas caracteristic este similar celui pe care l-am scris mai devreme. În loc să adăugăm opțiunea la matrice, o vom face unset aceasta:

/ ** * @Pentru opțiunea: opțiunea nu este încă configurată * / funcția publică theOptionIsNotYetConfigured ($ opțiune) $ config = include 'fixtures / config.php'; dacă (! is_array ($ config)) $ config = []; unset ($ config [$ opțiune]); $ content = "

Acest lucru nu este frumos. Stiu! Cu siguranță ne-ar putea refactoriza, deoarece ne repetă, dar asta nu este scopul acestui tutorial.

Cel de-al doilea pas caracteristic, de asemenea, pare familiar, și este în mare parte copie și lipire de la mai devreme:

/ ** * @Apoi să primesc valoarea implicită: implicit ca: opțiunea opțiune * / funcția publică iShouldGetDefaultValueAsOption ($ implicit, $ opțiune) $ actual = $ this-> config-> get ($ opțiune, $ implicit); // Taylor! dacă (! strcmp ($ default, $ actual) == 0) aruncați o nouă excepție ("Expected $ actual pentru a fi" $ default ".);  

obține() se întoarce nul. Să trecem la phpspec și să scriem un exemplu pentru a rezolva acest lucru:

funcția it_gets_a_default_value_when_option_is_not_set () $ this-> get ('foo', 'bar') -> shouldReturn ('bar'); $ this-> set ('foo', 'baz'); $ this-> obține ('foo', 'bar') -> shouldReturn ('baz');  

În primul rând, verificăm dacă obținem valoarea implicită dacă opțiunea nu este încă configurată. În al doilea rând, ne asigurăm că opțiunea implicită nu suprascrie o opțiune configurată.

La prima vedere, phpspec s-ar putea să pară ca o suprasolicitare în acest caz, deoarece deja aproape că încercăm același lucru cu Behat. Imi place sa folosesc phpspec pentru a specifica cazurile de margine, insa, care sunt implicite in scenariu. Și, de asemenea, generatoarele de coduri ale phpspec sunt cu adevărat minunate. Le folosesc pentru tot și mă găsesc lucrand mai repede ori de câte ori folosesc phpspec.

Acum, phpspec confirmă ce ne-a spus deja Behat:

$ vendor / bin / phpspec executa --format = destul de Config 10 ✔ este initializabil 15 ✔ primeste si stabileste o optiune de configurare 24 ✘ primeste o valoare implicita cand optiunea nu este setata asteptata "bar", dar a fost null ... 1 specificatii 3 exemple ( 2 au trecut, 1 nu a reușit) 9ms 

Pentru a reveni la verde, vom adăuga o "întoarcere timpurie" la obține() metodă:

funcția publică obține ($ opțiune, $ defaultValue = null) if (! isset ($ this-> setare [$ opțiune]) și $ is_null ($ defaultValue) return $ defaultValue; dacă (! isset ($ this-> settings [$ option])) returnați null; returneaza $ this-> settings [$ option];  

Vedem că phpspec este acum fericit:

$ vendor / bin / phpspec run --format = destul de config 10 ✔ este inițializabil 15 ✔ primește și stabilește o opțiune de configurare 24 ✔ primește o valoare implicită când opțiunea nu este setată 1 specificații 3 exemple (3 trecute) 9ms 

Și așa este Behat, și noi suntem.

S-a terminat cel de-al doilea scenariu și am lăsat unul. Pentru ultimul scenariu, trebuie doar să scriem definiția pasului pentru Și am setat opțiunea de configurare a "fusului orar" la "GMT" Etapa:

/ ** * @ Când am setat opțiunea de configurare a opțiunii la: valoare * / funcția publică iSetTheConfigurationOptionTo ($ opțiune, valoare $) $ this-> config-> set (opțiune $, valoare $); // Taylor!  

Deoarece am implementat deja a stabilit() , acest pas este deja verde:

$ vendor / bin / behat Caracteristică: fișiere de configurare Pentru a configura aplicația mea Ca dezvoltator trebuie să pot stoca opțiunile de configurare într-un fișier Scenariu: Obținerea unei opțiuni configurate # features / config.feature: 6 Având în vedere că există o configurație fișier # FeatureContext :: thereIsAConfigurationFile () Și opțiunea 'timezone' este configurată pentru 'UTC' # FeatureContext :: theOptionIsConfiguredTo () Când încărc fișierul de configurare # FeatureContext :: iLoadTheConfigurationFile () 'opțiune # FeatureContext :: iShouldGetAsOption () Scenariu: Obținerea unei opțiuni neconfigurate cu o valoare implicită # features / config.feature: 12 Dat fiind că există un fișier de configurare # FeatureContext :: thereIsAConfigurationFile () Și opțiunea' fusul orar ' încă configurate # FeatureContext :: theOptionIsNotYetConfigured () Când încărc fișierul de configurare # FeatureContext :: iLoadTheConfigurationFile () Apoi trebuie să obțin valoarea implicită 'CET' ca opțiune 'timezone' # FeatureContext :: iShould GetDefaultValueAsOption () Scenariu: Setarea unei opțiuni de configurare # features / config.feature: 18 Având în vedere existența unui fișier de configurare # FeatureContext :: thereIsAConfigurationFile () Și opțiunea 'timezone' este configurată pentru 'UTC' # FeatureContext :: theOptionIsConfiguredTo Încărcarea fișierului de configurare # FeatureContext :: iLoadTheConfigurationFile () Și am setat opțiunea de configurare a "zonei de fus orar" la "GMT" # FeatureContext :: iSetTheConfigurationOptionTo () Apoi trebuie să primesc opțiunea "GMT" ca opțiune de fus orar # FeatureContext :: iShouldGetAsOption ) 3 scenarii (3 trecute) 13 trepte (13 trecute) 0m0.04s (8.92Mb) 

Învelire

Totul este frumos și verde, așa că să ne întoarcem rapid și să vedem ce am realizat.

Am descris în mod eficient comportamentul extern al unui încărcător de fișiere de configurare, utilizând mai întâi abordarea lui Taylor și apoi utilizând o abordare tradițională BDD. Apoi, am implementat funcția, utilizând phpspec pentru a proiecta și descrie comportamentul intern. Exemplul la care lucrăm este destul de simplu, dar am acoperit elementele de bază. Dacă avem nevoie de o mai mare complexitate, putem extinde ceea ce deja avem. Utilizând BDD, avem cel puțin trei opțiuni:

  1. Dacă observăm un bug sau trebuie să schimbăm câteva intervale ale software-ului nostru, putem descrie că folosind phpspec. Scrieți un exemplu nereușind care prezintă bug-ul și scrieți codul necesar pentru a ajunge la verde.
  2. Dacă trebuie să adăugăm un nou caz de utilizare la ceea ce avem, putem adăuga un scenariu la  config.feature. Putem apoi să ne lucrăm în mod iterativ prin fiecare pas, folosind Behat și phpspec.
  3. Dacă trebuie să implementăm o nouă caracteristică, cum ar fi susținerea fișierelor configurări YAML, putem scrie o nouă caracteristică nouă și vom începe din nou, folosind abordarea pe care am folosit-o în acest tutorial.

Cu această configurație de bază, nu avem nici o scuză de a nu scrie un test sau un spec, înainte de a ne scrie codul. Ceea ce am construit este acum acoperit de teste, ceea ce va face mult mai ușor să lucrăm cu el în viitor. Adăugați la aceasta, că și codul nostru este complet documentat. Cazurile de utilizare intenționate sunt descrise în limba engleză, iar lucrările interne sunt descrise în specificațiile noastre. Aceste două lucruri vor face ca briza pentru alți dezvoltatori să înțeleagă și să lucreze cu baza de cod.

Sper că acest tutorial vă va ajuta să înțelegeți mai bine cum poate fi folosit BDD într-un context PHP, cu Behat și phpspec. Dacă aveți întrebări sau comentarii, vă rugăm să le postați mai jos în secțiunea de comentarii.

Mulțumesc că ați citit!

Cod