Een BDD-workflow met Behat en Phpspec

In deze zelfstudie zullen we twee verschillende BDD-tools, Behat en phpspec, bekijken en bekijken hoe ze u kunnen ondersteunen in uw ontwikkelingsproces. BDD leren kan verwarrend zijn. Nieuwe methodologie, nieuwe hulpmiddelen en veel vragen, zoals 'wat te testen?' en "welke tools te gebruiken?". Ik hoop dat dit vrij eenvoudige voorbeeld u ideeën zal geven over hoe u BDD kunt opnemen in uw eigen workflow.

Mijn inspiratie

Ik werd geïnspireerd om deze tutorial te schrijven door Taylor Otwell, maker van het Laravel-raamwerk. Meerdere keren heb ik Taylor horen uitleggen waarom hij meestal geen TDD / BDD doet door te zeggen dat hij graag eerst de API van zijn code plant, voordat hij daadwerkelijk begint met de implementatie ervan. Ik heb dit van veel ontwikkelaars gehoord en elke keer denk ik bij mezelf: "Maar dat is het perfecte gebruik van TDD / BDD!". Taylor zegt dat hij graag de API van zijn code in kaart brengt, door de code te schrijven die hij had dat hij had. Hij zal dan beginnen met coderen en niet tevreden zijn totdat hij die exacte API heeft bereikt. Het argument is logisch als je alleen op unitniveau test / speccing, maar met een tool zoals Behat, begin je met het externe gedrag van je software, wat eigenlijk, voor zover ik begrijp, wat Taylor wil bereiken.

Wat we zullen behandelen

In deze zelfstudie zullen we een eenvoudige configuratiebestand loaderklasse bouwen. We zullen beginnen met Taylor's benadering en in plaats daarvan naar een BDD-benadering overschakelen. De voorbeelden zijn minimalistisch, maar we zullen ons nog steeds zorgen moeten maken over armaturen, statische methoden, enzovoort. Dus al met al moeten ze volgens mij voldoende zijn om te laten zien hoe Behat en phpspec elkaar kunnen aanvullen.

Disclaimer: Allereerst is dit artikel geen Ermee beginnen gids. Het veronderstelt basiskennis van BDD, Behat en phpspec. U hebt waarschijnlijk al naar deze hulpmiddelen gekeken, maar worstelt nog steeds met de manier waarop u ze daadwerkelijk kunt gebruiken in uw dagelijkse workflow. Als je phpspec wilt opfrissen, bekijk dan mijn zelfstudie. Ten tweede gebruik ik Taylor Otwell als een voorbeeld. Ik weet helemaal niets over hoe Taylor werkt, naast wat ik hem in podcasts heb horen zeggen etc. Ik gebruik hem als een voorbeeld omdat hij een geweldige ontwikkelaar is (hij maakte Laravel!) En omdat hij bekend is. Ik had net zo goed iemand anders kunnen gebruiken, omdat de meeste ontwikkelaars, inclusief ikzelf, BDD niet altijd doen. Ik zeg ook niet dat de workflow die Taylor beschrijft slecht is. Ik vind het een briljant idee om wat na te denken over je code voordat je deze daadwerkelijk gaat schrijven. Deze tutorial is alleen bedoeld om de BDD-manier te tonen om dit te doen.

Taylor's workflow

Laten we beginnen met een blik op hoe Taylor zou kunnen gaan met het ontwerpen van deze configuratiebestandslader. Taylor zegt dat hij graag een leeg tekstbestand in zijn editor activeert en vervolgens schrijft hoe hij zou willen dat ontwikkelaars met zijn code (de API) kunnen werken. In een BDD-context wordt dit gewoonlijk aangeduid als het testen van het externe gedrag van software en hulpmiddelen zoals Behat zijn hier geweldig voor. We zullen dit in een korte tijd zien.

Ten eerste, misschien zal Taylor een beslissing nemen over de configuratiebestanden. Hoe zouden ze moeten werken? Net als in Laravel, gebruiken we eenvoudige PHP-arrays. Een voorbeeld van een configuratiebestand kan er als volgt uitzien:

# config.php  'UTC', );

Vervolgens, hoe moet de code die gebruikmaakt van dit configuratiebestand werken? Laten we dit op de Taylor-manier doen en gewoon de code schrijven die we wilden dat we hadden:

$ config = Config :: load ('config.php'); $ Config-> get ( 'timezone'); // geeft 'UTC' $ config-> get terug ('tijdzone', 'CET'); // geeft 'CET' als resultaat als 'tijdzone' niet is geconfigureerd $ config-> set ('tijdzone', 'GMT'); $ Config-> get ( 'timezone'); // geeft 'GMT' terug 

Oké, dus dit ziet er goed uit. Eerst hebben we een statische oproep naar a laden() functie, gevolgd door drie use-cases: 

  1. Haal de "tijdzone" uit het configuratiebestand. 
  2. Een standaardwaarde krijgen als de "tijdzone" nog niet is geconfigureerd. 
  3. Een configuratieoptie wijzigen met omgeving het naar iets anders. We zullen elk van deze use-cases beschrijven, of scenario's, met Behat in een korte tijd.

Het is logisch om Behat voor dit soort dingen te gebruiken. Behat zal ons niet dwingen om ontwerpbeslissingen te nemen - we hebben daar phpspec voor. We zullen de vereisten, die we zojuist beschreven hebben, gewoon in een Behat veranderen voorzien zijn van om ervoor te zorgen dat we het goed krijgen, wanneer we beginnen met bouwen. Onze behat-functie zal dienen als een acceptatietest voor onze eisen bij wijze van spreken.

Als je kijkt naar de code die we hebben geschreven, is een andere reden om Behat te gebruiken in plaats van alleen phpspec, de statische aanroep. Het is niet eenvoudig om statische methoden te testen, vooral niet als u alleen een hulpmiddel zoals phpspec gebruikt. We zullen zien hoe we dit kunnen aanpakken als we zowel Behat en phpspec beschikbaar hebben.

Opstelling

Ervan uitgaande dat u Composer gebruikt, is het instellen van Behat en phspec een supereenvoudig proces in twee stappen.

Ten eerste heb je een basis nodig composer.json het dossier. Deze bevat Behat en phpspec en gebruikt psr-4 om de klassen automatisch te laden:

"require-dev": "behat / behat": "~ 3.0", "phpspec / phpspec": "~ 2.0", "autoload": "psr-4": "": "src /"  

Rennen componist installeren om de afhankelijkheden op te halen.

phpspec heeft geen configuratie nodig om te kunnen werken, terwijl Behat je nodig heeft om het volgende commando uit te voeren om een ​​basissteiger te genereren:

$ vendor / bin / behat --init

Dat is alles wat nodig is. Dit kan niet je excuus zijn om BDD niet te doen!

De functies plannen met Behat

Dus nu we allemaal klaar zijn, zijn we klaar om BDD te gaan doen. Omdat BDD betekent het installeren en gebruiken van Behat en phpspec, toch??

Wat mij betreft zijn we al begonnen met BDD. We hebben het externe gedrag van onze software effectief beschreven. Onze "klanten" in dit voorbeeld zijn ontwikkelaars, die gaan communiceren met onze code. Met "effectief" bedoel ik dat we het gedrag hebben beschreven op een manier die ze zullen begrijpen. We kunnen de code gebruiken die we al hebben geschetst, deze in een README-bestand plaatsen en elke fatsoenlijke PHP-ontwikkelaar zou het gebruik ervan begrijpen. Dus dit is eigenlijk best goed, maar ik heb hier twee belangrijke dingen op te merken. Allereerst werkt het beschrijven van het gedrag van software met behulp van code alleen in dit voorbeeld omdat de "clients" programmeurs zijn. Normaal testen we iets dat door 'normale' mensen zal worden gebruikt. Een menselijke taal is beter dan PHP wanneer we met mensen willen communiceren. Ten tweede, waarom dit niet automatiseren? Ik ga niet beweren waarom dit een goed idee zou kunnen zijn.

Dat gezegd zijnde, ik denk dat het beginnen met het gebruik van Behat nu een redelijke beslissing zou zijn.

Met Behat willen we elk van de scenario's beschrijven die we hierboven hebben geschetst. We willen niet elke casus uitgebreid bespreken die te maken heeft met het gebruik van de software. We hebben phpspec beschikbaar als dit nodig zou zijn om bugs onderweg op te lossen enz. Ik denk dat veel ontwikkelaars, misschien inclusief Taylor, het gevoel hebben dat ze alles moeten overdenken en alles moeten beslissen voordat ze tests en specificaties kunnen schrijven. Dat is waarom ze ervoor kiezen om zonder BDD te beginnen, omdat ze niet alles van tevoren willen beslissen. Dit is niet het geval met Behat, omdat we het externe gedrag en gebruik beschrijven. Als u Behat wilt gebruiken om een ​​functie te beschrijven, hoeven we niet verder te beslissen dan in het bovenstaande voorbeeld met het gebruik van een onbewerkt tekstbestand. We hoeven alleen maar de vereisten van de functie te definiëren - in dit geval de externe API van de klasse van de configuratiebestanden.

Laten we nu de bovenstaande PHP-code nemen en deze veranderen in een Behat-functie, gebruikmakend van de Engelse taal (eigenlijk de Gherkin-taal gebruiken).

Maak een bestand in de Kenmerken/ map, genaamd config.feature, en vul de volgende scenario's in:

Functie: configuratiebestanden Om mijn applicatie te configureren Als ontwikkelaar moet ik configuratie-opties in een bestand kunnen opslaan Scenario: een geconfigureerde optie krijgen Gegeven is er een configuratiebestand En de optie 'tijdzone' is geconfigureerd naar 'UTC' wanneer Ik laad het configuratiebestand. Dan moet ik de optie 'UTC' als 'tijdzone' gebruiken Scenario: een niet-geconfigureerde optie met een standaardwaarde verkrijgen Gegeven er is een configuratiebestand En de optie 'tijdzone' is nog niet geconfigureerd Wanneer ik de configuratie laad bestand Dan zou ik standaardwaarde 'CET' moeten krijgen als 'tijdzone'-optie Scenario: een configuratie-optie instellen Gegeven is er een configuratiebestand En de optie' tijdzone 'is geconfigureerd naar' UTC 'Wanneer ik het configuratiebestand laad En ik stel de' tijdzone 'configuratieoptie naar' GMT 'Dan zou ik de optie' GMT 'als' tijdzone 'moeten krijgen 

In deze functie beschrijven we van buitenaf hoe "een ontwikkelaar" configuratie-opties kan opslaan. Wij geven niet om het interne gedrag - dat zullen we doen als we phpspec gaan gebruiken. Zolang deze functie groen is, maakt het ons niet uit wat er achter de schermen gebeurt.

Laten we Behat gebruiken en kijken wat het van onze functie vindt:

$ vendor / bin / behat --dry-run --append-snippets 

Met deze opdracht laten we Behat de benodigde stapdefinities toevoegen aan onze featurecontext. Ik zal niet veel ingaan op details over Behat, maar dit voegt een aantal lege methoden toe aan ons FeatureContext klasse die verwijst naar onze functiestappen hierboven.

Bekijk als voorbeeld de stapdefinitie die Behat heeft toegevoegd voor de er is een configuratiebestand stap die we gebruiken als de stap "Gegeven" in alle drie de scenario's:

/ ** * @Given er is een configuratiebestand * / public function thereIsAConfigurationFile () gooi nieuwe PendingException ();  

Nu, alles wat we moeten doen is een code invullen om dit te beschrijven.

Step-definities schrijven

Voordat we beginnen, heb ik twee belangrijke opmerkingen over de stap-definities:

  1. Het punt is om te bewijzen dat het gedrag nu niet is zoals we willen. Daarna kunnen we beginnen met het ontwerpen van onze code, meestal met phpspec, om groen te worden.
  2. De implementatie van de stapdefinities is niet belangrijk - we hebben alleen iets nodig dat werkt en het bereikt "1". We kunnen later refactoren.

Als je rent verkoper / bin / Behat, je zult zien dat alle scenario's nu in behandeling zijn.

We beginnen met de eerste stap Gegeven dat er een configuratiebestand is. We zullen een fixture van het configuratiebestand gebruiken, zodat we de static kunnen gebruiken laden() methode later. We geven om het statische laden() methode omdat het ons een mooie API geeft Config :: load (), heel erg zoals de Laravel-Voorgevels. Deze stap kan op verschillende manieren worden geïmplementeerd. Voor nu denk ik dat we er alleen voor moeten zorgen dat we de fixture beschikbaar hebben en dat deze een array bevat:

/ ** * @Given er is een configuratiebestand * / public function thereIsAConfigurationFile () if (! File_exists ('fixtures / config.php')) gooit nieuwe uitzondering ('File' fixtures / config.php 'not found') ; $ config = include 'fixtures / config.php'; als (! is_array ($ config)) nieuwe uitzondering gooit ("File 'fixtures / config.php' moet een array bevatten");  

We gaan met deze stap groen worden zonder enige code te implementeren naast het maken van het armatuur. Het doel van a Gegeven stap is om het systeem in een bekende staat te brengen. In dit geval betekent dit dat we ervoor moeten zorgen dat we een configuratiebestand hebben.

Om onze eerste groene stap te zetten, hoeven we alleen maar de armatuur te maken:

# fixtures / config.php 

Vervolgens hebben we een En stap, die in dit geval slechts een alias is Gegeven. We willen er zeker van zijn dat het configuratiebestand een optie voor de tijdzone bevat. Nogmaals, dit is alleen gerelateerd aan onze competitie, dus we geven er niet veel om. Ik sloeg de volgende (hackish) code samen om dit te bereiken:

/ ** * @Gegeven de optie: optie is geconfigureerd om: value * / public function theOptionIsConfiguredTo ($ option, $ value) $ config = include 'fixtures / config.php'; if (! is_array ($ config)) $ config = []; $ config [$ option] = $ waarde; $ content = "

De bovenstaande code is niet mooi, maar het volbrengt wat het moet doen. Hiermee kunnen we onze fixture manipuleren vanuit onze functie. Als u Behat uitvoert, ziet u dat de optie "tijdzone" is toegevoegd aan de config.php armatuur:

 'UTC', ); 

Dit is het moment om een ​​deel van de originele 'Taylor-code' in te voeren! De stap Wanneer ik het configuratiebestand laad zal bestaan ​​uit code waar we echt om geven. We zullen een deel van de code van het onbewerkte tekstbestand van vroeger invoeren en zorgen dat deze wordt uitgevoerd:

/ ** * @ Wanneer ik het configuratiebestand laad * / public function iLoadTheConfigurationFile () $ this-> config = Config :: load ('fixtures / config.php'); // Taylor! 

Running Behat, natuurlijk zal dit mislukken, sinds config bestaat nog niet. Laten we phpspec ter redding brengen!

Ontwerpen met Phpspec

Wanneer we Behat uitvoeren, krijgen we een fatale foutmelding:

PHP Fatale fout: Klasse 'Config' niet gevonden ... 

Gelukkig hebben we phpspec beschikbaar, inclusief de geweldige codegeneratoren:

$ vendor / bin / phpspec desc "Config" Specificatie voor Config aangemaakt in ... /spec/ConfigSpec.php. $ vendor / bin / phpspec run --format = pretty Wil je dat ik 'Config' voor je maak? y $ vendor / bin / phpspec run --format = pretty Config 10 ✔ is instelbaar 1 specs 1 voorbeelden (1 gepasseerd) 7ms 

Met deze commando's heeft phpspec de volgende twee bestanden voor ons gemaakt:

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

Hierdoor zijn we de eerste fatale fout kwijt, maar Behat werkt nog steeds niet:

PHP Fatale fout: aanroep op ongedefinieerde methode Config :: load () in ... 

laden() gaat een statische methode zijn en wordt daarom niet gemakkelijk gespeculeerd met phpspec. Om twee redenen is dit echter OK:

  1. Het gedrag van de laden() methode zal heel eenvoudig zijn. Als we later meer complexiteit nodig hebben, kunnen we logica extraheren naar kleine testbare methoden.
  2. Het gedrag, zoals nu, is goed genoeg gedekt door Behat. Als de methode het bestand niet correct in een array laadt, zal Behat ons verbazen.

Dit is een van die situaties waarin veel ontwikkelaars de muur zullen raken. Ze zullen phpspec weggooien en concluderen dat het rotzooi is en tegen hen werkt. Maar zie hoe mooi Behat en phpspec elkaar hier aanvullen?

In plaats van te proberen om 100% dekking te krijgen met phpspec, laten we gewoon een simpele implementeren laden() functie en vertrouw erop dat het wordt gedekt door Behat:

instellingen = array ();  openbare statische functie laden ($ path) $ config = new static (); if (file_exists ($ path)) $ config-> settings = include $ path; return $ config;  

We zijn er vrij zeker van dat onze configuratie-opties nu zijn geladen. Zo niet, dan zullen de rest van onze stappen mislukken en kunnen we hier opnieuw naar kijken.

De functie opbouwen met iteratie

Terug naar groen met zowel Behat en phpspec, we kunnen nu naar onze volgende functiestap kijken Dan zou ik de optie 'UTC' als 'tijdzone' moeten krijgen.

/ ** * @Then zou ik moeten krijgen: waarde als: optie optie * / publieke functie iShouldGetAsOption ($ value, $ option) $ actual = $ this-> config-> get ($ option); // Taylor! if (! strcmp ($ value, $ actual) == 0) werp een nieuwe uitzondering ("Verwachte $ actual wordt '$ option'.");  

In deze stap schrijven we meer van die code die we wilden dat we hadden. Maar als we Behat gebruiken, zullen we zien dat we geen a hebben krijgen() methode beschikbaar:

PHP Fatale fout: aanroep op ongedefinieerde methode Config :: get () in ... 

Het is tijd om terug te keren naar phpspec en dit uit te zoeken.

Het testen van accessors en mutators, AKA-getters en setters, is bijna hetzelfde als dat oude kip- of eidoillemma. Hoe kunnen we het testen krijgen() methode als we nog niet de set () methode en vice versa. Hoe ik dit aanpas, is door ze in één keer te testen. Dit betekent dat we de functionaliteit daadwerkelijk gaan gebruiken om een ​​configuratieoptie in te stellen, ook al hebben we dat scenario nog niet bereikt.

Het volgende voorbeeld zou moeten doen:

function it_gets_and_sets_a_configuration_option () $ this-> get ('foo') -> shouldReturn (null); $ this-> set ('foo', 'bar'); $ This-> krijgen ( 'foo') -> shouldReturn ( 'bar');  

Eerst zullen we de phpspec-generators helpen ons op weg te helpen:

$ vendor / bin / phpspec run --format = pretty Wil je dat ik 'Config :: get ()' voor je maak? y $ vendor / bin / phpspec run --format = pretty Wil je dat ik 'Config :: set ()' voor je maak? y $ vendor / bin / phpspec run --format = pretty Config 10 ✔ kan geïnitialiseerd worden 15 ✘ krijgt en stelt een configuratie-optie verwacht "bar" in, maar krijgt null ... 1 specs 2 voorbeelden (1 geslaagd, 1 mislukt) 9ms 

Laten we nu terug naar groen gaan:

public function get ($ option) if (! isset ($ this-> settings [$ option])) return null; return $ this-> settings [$ option];  openbare functieset ($ -optie, $ -waarde) $ dit-> instellingen [$ -optie] = $ waarde;  

En daar gaan we:

$ vendor / bin / phpspec run --format = pretty Config 10 ✔ is instelbaar 15 ✔ krijgt en stelt een configuratieoptie in 1 specs 2 voorbeelden (2 doorgegeven) 9ms 

Dat bracht ons een lange weg. Running Behat, we zien dat we nu ver in het tweede scenario zitten. Vervolgens moeten we de standaardoptiefunctie implementeren, aangezien krijgen() komt net terug nul nu.

Eerste stap van de functie is vergelijkbaar met degene die we eerder hebben geschreven. In plaats van de optie aan de array toe te voegen, zullen we dat doen ongezet het:

/ ** * @ Gegeven de optie: optie is nog niet geconfigureerd * / publieke functie theOptionIsNotYetConfigured ($ option) $ config = include 'fixtures / config.php'; if (! is_array ($ config)) $ config = []; unset ($ config [$ optie]); $ content = "

Dit is niet mooi. Ik weet! We zouden het zeker kunnen refacteren, omdat we onszelf herhalen, maar dat is niet de reikwijdte van deze tutorial.

De tweede functiestap ziet er ook vertrouwd uit en is meestal kopiëren en plakken van eerder:

/ ** * @Then zou ik standaardwaarde moeten krijgen: standaard als: optie optie * / publieke functie iShouldGetDefaultValueAsOption ($ default, $ option) $ actual = $ this-> config-> get ($ option, $ default); // Taylor! if (! strcmp ($ default, $ actual) == 0) werp een nieuwe uitzondering ("Verwachte $ actual wordt '$ default'.");  

krijgen() komt terug nul. Laten we naar phpspec springen en een voorbeeld schrijven om dit op te lossen:

function it_gets_a_default_value_when_option_is_not_set () $ this-> get ('foo', 'bar') -> shouldReturn ('bar'); $ this-> set ('foo', 'baz'); $ this-> get ('foo', 'bar') -> shouldReturn ('baz');  

Eerst controleren we of we de standaardwaarde krijgen als 'optie' nog niet is geconfigureerd. Ten tweede zorgen we ervoor dat de standaardoptie een geconfigureerde optie niet overschrijft.

Op het eerste gezicht lijkt phpspec in dit geval overdreven, aangezien we bijna hetzelfde met Behat al aan het testen zijn. Ik gebruik graag phpspec om de edge-cases te specificeren, die in het scenario worden geïmpliceerd. En ook, de codegeneratoren van phpspec zijn echt geweldig. Ik gebruik ze voor alles en ik merk dat ik sneller werk als ik phpspec gebruik.

Nu bevestigt phpspec wat Behat ons al heeft verteld:

$ vendor / bin / phpspec run --format = pretty Config 10 ✔ kan geïnitialiseerd worden 15 ✔ krijgt en stelt een configuratieoptie in 24 ✘ krijgt een standaardwaarde wanneer de optie niet is ingesteld "bar", maar krijgt nul ... 1 specs 3 voorbeelden ( 2 geslaagd, 1 mislukt) 9ms 

Om weer groen te worden, voegen we een 'vroege terugkeer' toe aan de krijgen() methode:

public function get ($ option, $ defaultValue = null) if (! isset ($ this-> settings [$ option]) and! is_null ($ defaultValue)) return $ defaultValue; if (! isset ($ this-> settings [$ option])) return null; return $ this-> settings [$ option];  

We zien dat phpspec nu gelukkig is:

$ vendor / bin / phpspec run --format = pretty Config 10 ✔ is instelbaar 15 ✔ verkrijgt en stelt een configuratieoptie in 24 ✔ krijgt een standaardwaarde wanneer optie niet is ingesteld 1 specs 3 voorbeelden (3 geslaagd) 9ms 

En zo is Behat, en wij ook.

We zijn klaar met ons tweede scenario en hebben er nog één te gaan. Voor het laatste scenario hoeven we alleen de stapdefinitie voor de te schrijven En ik heb de configuratie-optie 'tijdzone' ingesteld op 'GMT' stap:

/ ** * @Wanneer ik de: optie configuratie-optie instelt op: waarde * / publieke functie iSetTheConfigurationOptionTo ($ option, $ value) $ this-> config-> set ($ option, $ value); // Taylor!  

Aangezien we het set () methode, deze stap is al groen:

$ vendor / bin / behat Feature: Configuratiebestanden Om mijn applicatie te configureren Als ontwikkelaar moet ik configuratie-opties in een bestand kunnen opslaan Scenario: Een geconfigureerde optie krijgen # features / config.feature: 6 Gegeven is er een configuratie bestand # FeatureContext :: thereIsAConfigurationFile () En de optie 'tijdzone' is geconfigureerd naar 'UTC' # FeatureContext :: theOptionIsConfiguredTo () Wanneer ik het configuratiebestand laad # FeatureContext :: iLoadTheConfigurationFile () Dan moet ik 'UTC' als 'tijdzone krijgen 'option # FeatureContext :: iShouldGetAsOption () Scenario: een niet-geconfigureerde optie met een standaardwaarde # features / config.feature: 12 Gegeven is er een configuratiebestand # FeatureContext :: thereIsAConfigurationFile () En de optie' tijdzone 'is niet nog geconfigureerd # FeatureContext :: theOptionIsNotYetConfigured () Wanneer ik het configuratiebestand laad # FeatureContext :: iLoadTheConfigurationFile () Dan zou ik standaardwaarde 'CET' moeten krijgen als 'tijdzone'-optie # FeatureContext :: iShould GetDefaultValueAsOption () Scenario: instellen van een configuratie-optie # features / config.feature: 18 Gegeven is er een configuratiebestand # FeatureContext :: thereIsAConfigurationFile () En de optie 'tijdzone' is geconfigureerd naar 'UTC' # FeatureContext :: theOptionIsConfiguredTo () When Ik laad het configuratiebestand # FeatureContext :: iLoadTheConfigurationFile () En ik zet de 'timezone' configuratie-optie op 'GMT' # FeatureContext :: iSetTheConfigurationOptionTo () Dan moet ik 'GMT' als 'tijdzone'-optie # FeatureContext :: iShouldGetAsOption ( ) 3 scenario's (3 geslaagd) 13 stappen (13 geslaagd) 0m0.04s (8.92Mb) 

Afronden

Alles is mooi en groen, dus laten we een snelle afronding hebben en kijken wat we hebben bereikt.

We hebben het externe gedrag van een configuratiebestand-lader effectief beschreven, eerst door Taylor's aanpak te gebruiken en vervolgens door een traditionele BDD-benadering te gebruiken. Vervolgens hebben we de functie geïmplementeerd, met behulp van phpspec om het interne gedrag te ontwerpen en beschrijven. Het voorbeeld waaraan we hebben gewerkt is vrij eenvoudig, maar we hebben de basis besproken. Als we meer complexiteit nodig hebben, kunnen we gewoon uitbreiden wat we al hebben. Met BDD hebben we ten minste drie opties:

  1. Als we een bug waarnemen of een paar internalen van onze software moeten wijzigen, kunnen we dat beschrijven met phpspec. Schrijf een foutvoorbeeld waarin de bug wordt weergegeven en schrijf de code die nodig is om groen te worden.
  2. Als we een nieuwe use-case moeten toevoegen aan wat we hebben, kunnen we een scenario toevoegen  config.feature. We kunnen dan iteratief elke stap doorlopen, met behulp van Behat en phpspec.
  3. Als we een nieuwe functie moeten implementeren, zoals het ondersteunen van YAML-configuratiebestanden, kunnen we een geheel nieuwe functie schrijven en opnieuw beginnen, met behulp van de aanpak die we in deze zelfstudie hebben gebruikt..

Met deze basisconfiguratie hebben we geen excuses om geen falende test of spec te schrijven, voordat we onze code schrijven. Wat we hebben gebouwd, wordt nu gedekt door tests, waardoor het in de toekomst veel gemakkelijker zal zijn om ermee te werken. Voeg daaraan toe dat onze code ook volledig gedocumenteerd is. De beoogde gebruiksgevallen worden beschreven in gewoon Engels en de interne werking wordt beschreven in onze specificaties. Deze twee dingen maken het een koud kunstje voor andere ontwikkelaars om de codebase te begrijpen en ermee te werken.

Ik hoop dat deze tutorial je heeft geholpen om beter te begrijpen hoe BDD kan worden gebruikt in een PHP-context, met Behat en phpspec. Als u vragen of opmerkingen heeft, kunt u deze hieronder posten in de sectie Opmerkingen.

Bedankt voor het lezen!