Dagens programmerare använder allt fler agila metoder i sitt dagliga arbete. Även projekt som följer den vanliga livscykeln för programvaruutveckling kan dra nytta av att anpassa sig till dem. Automatiska tester och TDD ger oss större förtroende för vårt arbete, underlättar implementeringen av ändringar i befintliga funktioner och leder oss ofta till bättre koddesign. Men nu räcker det inte längre. Vi måste driva fördelarna med tester till det yttersta och BDD gör det möjligt.BDD bygger vidare på TDD och tillför mycket värde till dess metoder. Det ger ett allmängiltigt språk i projektet och möjliggör bättre kommunikation mellan kund och utvecklare. Det erbjuder mycket för projektledare och chefer, men gör också livet för en utvecklare mycket enklare. Genom att följa BDD-principerna får vi tydliga krav, testerna blir lättare att förstå och de kan fungera som dokumentation. BDD flyttar fokus från testobjekten och ger oss förtroende för att vi testar det vi ska testa - beteendet.
Om du använder TDD är det lätt att börja med BDD - det är i princip en uppsättning bästa praxis för det. BDD har en uppsättning enkla regler som talar om hur man skriver specifikationer och vad man ska testa. Specifikationerna är indelade i tre delar: Given (ställa upp testvillkor), When (påkalla åtgärd på ämnet) och Then (påståenden). Tester bör ha beskrivande namn och befintliga testramverk gör det möjligt att använda metoder och påståenden som liknar naturligt språk - allt detta sammantaget ger oss tester som är läsbara för både tekniska och icke-tekniska användare. Bra namnkonventioner visar sig vara användbara under regressionstester.
BDD innehåller också en uppsättning riktlinjer för testpersoner. I motsats till TDD flyttas fokus från testning av implementering till testning av beteende - och genom att använda detta leder det till bättre design och ger mer flexibilitet när förändringar måste införas. Specifikationer bör vara som skrivna och körbara kundkrav - de på hög nivå bör fungera som acceptanstester. Målet är att skriva tester på ett sätt som gör att de bara behöver ändras när kraven ändras. Att använda BDD ger oss förtroende för att vi testar det som verkligen behöver täckas och det är ett mer pragmatiskt tillvägagångssätt än TDD.
Om du vill se BDD i aktion rekommenderar vi Ruby. Det är ett kraftfullt och roligt språk att använda och det har en utmärkt BDD-verktygssats.
Gurka
Cucumber är det mest populära ramverket för BDD i Ruby. Det introducerar ett speciellt språk, kallat Gherkin, som du kommer att skriva dina tester i. Till skillnad från RSpec är funktioner som beskrivs i Gherkin vanlig text, inte kodoch som sådan kan - och bör - förstås av vem som helst, i synnerhet av kunden.
Cucumber-funktionen ser ut så här (exemplet är hämtat från Cucumber wiki):
Funktion: En kortfattad men beskrivande text om vad som önskas
Textuell beskrivning av affärsvärdet av denna funktion
Affärsregler som styr funktionens omfattning
Eventuell ytterligare information som gör funktionen lättare att förstå
Scenario: Någon bestämbar affärssituation
Givet vissa förutsättningar
Och något annat förhandsvillkor
När någon handling av aktören
Och någon annan åtgärd
Och ytterligare en åtgärd
Då uppnås något testbart resultat
Och något annat som vi kan kontrollera händer också
Scenario: En annan situation
...
Funktionerna kommer att beskrivas mer i detalj senare.
Använda gurka i Ruby on Rails
Installation
Första steget för att använda Cucumber i din projekt installerar det. Lägg bara till dessa två gems i din Gemfile:
grupp :test do
gem 'cucumber-rails', :require => false
gem 'databas_rensare'
slut
Samla dem genom att köra paketinstallationoch generera Cucumber-skript och -kataloger med följande kommando:
rails genererar cucumber:installera
Detta kommer att skapa konfiguration/cucumber.yml, skript/gurka och funktioner/ katalog, som kommer att innehålla .funktion filer, samt stegdefinitioner och stödfiler. För att köra dina funktioner använder du ett nytt rake-kommando:
kratta gurka
Funktioner
Låt oss ta en närmare titt på funktioner. En funktion är något som din applikation har eller gör - till exempel skickar nyhetsbrev med jämna mellanrum eller låter användaren dela sina foton offentligt. En funktion består av flera scenarier som beskriver hur den här funktionen fungerar i olika sammanhang.
För att demonstrera grundläggande användning av Cucumber i Rails skriver vi en funktion från grunden. Denna exempelfunktion kommer att vara den första vi skriver i applikationen, som kommer att visas i den inkommande andra delen av denna artikel. Den här applikationen gör det möjligt för användaren att skapa artiklar och butiker (butiker säljer artiklar) och sedan skapa inköpslistor.
I den enklaste versionen visar programmet, efter att ha sammanställt inköpslistan, i vilka butiker de varor som användaren vill ha är billigast.
Skapa först en ny fil med namnet skapa_artikel.funktion i funktioner/ katalog. Längst upp i en .funktion fil finns det en Funktion nyckelord, följt av en kort beskrivning av det. Till exempel:
Funktion: Skapa föremål
På följande rader kan du skriva ett affärsmål som kommer att implementera denna funktion. Eftersom Cucumber ignorerar text som skrivs före det första scenariot är det inte nödvändigt att skriva något, men det är definitivt en bra idé.
För att enkelt kunna skapa inköpslistor med varor som säljs i närliggande butiker
Som användare
Jag vill lägga till artiklar i systemet
I utdraget kan du se ett ganska populärt mönster ovan som du kan använda för att beskriva affärsmål. Det består av tre delar: varför är funktionen nödvändig, vem vill ha den och vad är den. Du behöver naturligtvis inte följa det här formatet, men se till att du inkluderar svar på dessa tre frågor i din beskrivning.
Scenarier
Därefter skriver vi några scenarier. Varje scenario inleds med nyckelordet "Scenario" och innehåller flera steg.
Scenario: skapa ett unikt objekt
Givet att det finns ett "mjölk"-objekt
När jag går till huvudsidan
Och jag skapar "Bröd"-artikeln
Då ser jag "Bröd" i artikelförteckningen
Om någon har skapat en artikel med namnet Milk är det alltså möjligt att skapa Bread, vilket resulterar i att Bread visas i artikelförteckningen. Vi bör inte testa om det går att skapa en post i databasen, eftersom detta faktum inte har något verkligt värde för kunden.
Scenariots steg använder tre huvudnyckelord:
Givet, för att ge sammanhang till scenariot
När, för att beskriva åtgärder
Sedan, för beskrivning av resultat
Det är viktigt att notera att Cucumber ignorerar nyckelordssteget som det börjar med och bara matchar den senare delen. Du kan alltså börja dina steg med "And" varhelst det känns naturligt. Den enda regeln för att välja rätt nyckelord är att scenariot måste vara lätt att förstå.
Steg definitioner
När du kör Cucumber får du nu följande resultat:
[...]
Funktion: Skapa artiklar
För att enkelt kunna skapa inköpslistor med varor som säljs i närliggande butiker
Som användare
Jag vill lägga till artiklar i systemet
Scenario: skapa en unik artikel # features/create_item.feature:6
Givet att det finns en "mjölk"-artikel # features/create_item.feature:7
Odefinierat steg: "det finns ett "mjölk"-föremål" (Cucumber::Odefinierad)
[...]
Det beror på att Cucumber inte vet vad vi menar när vi säger "det finns en mjölkvara". För att ge dina steg någon mening måste du definiera dem i steg_definitioner katalog.
Ett rekommenderat sätt att organisera dina stegdefinitioner är att dela upp dem efter domän. Till exempel tillhör de flesta av de steg vi har skapat Item-domänen. Därför bör vi skapa en fil med namnet steg_definitioner/item_steps.rb och placera följande kod där:
Givet "det finns en "$name" artikel" gör |namn|
Tillverka :objekt, namn: namn
slut
När "jag skapar ett "$name"-objekt" do |name|
inom "#new_item" do
fyll_i "Namn", med: namn
klicka_på "Skapa"
slut
slut
Then "Jag ser "$name" i artikelförteckningen" do |name|
inom ".items" do
expect(page).to har_innehåll namn
slut
slut
Stegdefinitionerna kommer vanligtvis att baseras på Capybara. Om du inte är bekant med Capybara, se till att kolla in länkarna i slutet av den här artikeln.
Det finns ytterligare ett steg som behöver definieras och det passar inte riktigt in i Item-stegen. Du skulle kunna lägga in det i huvud_sida_steg.rb:
När "Jag går till huvudsidan" gör
besök root_path
slut
Slutsats
Det här är en mycket enkel story för en mycket enkel funktion. Syftet var att demonstrera kärnkoncepten i BDD som de används i Cucumber. Att skriva bra stories kräver dock lite mer. Som utvecklare måste du ändra ditt tankesätt helt och hållet - glöm implementeringen och fokusera på affärsmålen istället. Cucumber gör denna övergång enklare med sin smarta användning av berättelser i klartext.