bdd: feature this! - yolk recruitment · specflow (.net) lettuce (python) jbehave ... testing...
TRANSCRIPT
BDD: Feature this!
Hello!I am Fred HeathYou can find me at
◇ @FredAtBootstrap◇ [email protected]
What’s this about
❏ Introduction❏ The Whys and Hows❏ Common mistakes and how to avoid them
BDD
Burning the toast
The old way
The BDD way
Features
Step definitions
Code
BDD Tools
◇ Cucumber (Ruby, Java)◇ CucumberJS (JavaScript)◇ SpecFlow (.NET)◇ Lettuce (Python)◇ JBehave (Java)◇ Behat (PHP)
Why BDD?
◇ Everyone talks the same language◇ Expectations are fully understood◇ Living documentation◇ Measurable progress◇ Considerable bug reduction
30% bugs per cycle to 2%
http://www.belatrixsf.com/index.php/whitepapers-successful-project-with-behavior-driven-development
Happy side effects: Case studies
Zero known defects
http://www.capita-itps.co.uk/media/127798/BDD-Case-study-2.pdf
TDD vs BDD?◇ Dev POV◇ Testing◇ Inside out◇ Assertions◇ Bug reduction as the
objective
◇ Actor POV◇ Specification◇ Outside in◇ Communication◇ Bug reduction as a
side-effect
“BDD is a communication and collaboration methodology (which happens to facilitate end-to-end testing)
TL;DR
Rule #1Everyone works together!
Rule #2Features must be readable by anyone and everyone
Scenario: View an online meetingGiven I go to domain “http:/myapp.com”, path “/meeting”,
port 80, query parameter ‘meetid=8763652733’When I click on HTML element at XPath
“/local/meeting/view[@class=’btn’]” Then the ‘onclick()’ function (in JS/myscript.js) is triggered for HTML element with id=’meeting1’And the Redis hash with a key ‘meet123’ is set to ‘viewed’And the database trigger tg_upd_meeting is firedAnd the HTML template view_meeting.haml is loaded
Readability: No technical details
Readability: BackgroundFeature: Change PIN
Background:Given I have been issued a new cardAnd I insert the card, entering the correct PINAnd I choose "Change PIN" from the menu
Scenario: Change PIN successfullyWhen I change the PIN to 1234Then the system should remember my PIN is now 1234
Scenario: Try to change PIN to the same as beforeWhen I try to change the PIN to the original PIN numberThen I should see a warning messageAnd the system should not have changed my PIN
Readability: OutlinesFeature: Addition
Scenario Outline: Add two numbersGiven the input "<input>"When the calculator is runThen the output should be "<output>"
Examples:| input | output || 2+2 | 4 || 98+1 | 99 |
Readability: Tags
@slow @reporting @nightlyScenario: Generate data analysis reportGiven I am logged inAnd there is a report "Total widget sales history"…
Timing: @daily, @peak, @nightlyDependencies: @database, @memcache, @proxyProgress: @wip, @todo, @done, @blockedFunctionality: @ux, @analytics, @middlewareEnvironment: @dev, @test, @stage, @live
Readability: SeguesScenario: Upgrade MembershipWhen I upgrade to the Pro planThen I see a message confirming the upgradeAnd I see that I am now on the Pro planAnd I receive the membership details by emailAnd the database keeps a record of when the upgrade happenedAnd an invoice for the upgrade is generatedAnd a PayPal request is generated
Readability: SeguesScenario: Upgrade MembershipWhen I upgrade to the Pro planThen the following happens: * I see a message confirming the upgrade * I see that I am now on the Pro plan * I receive the membership details by email * the database keeps a record of when the upgrade happened * an invoice for the upgrade is generated * a PayPal request is generated
Scenario: User creates some sites and circuits, check connected sites list Given a "site" exists with {"name"=>"Somewhere1", "identifier" => "TER1", "provider"=>"TER1 Provider"} And a "site" exists with {"name"=>"Somewhere2", "identifier" => "TER2", "provider"=>"Some Provider"} And a "site" exists with {"name"=>"Somewhere3", "identifier" => "TER3", "provider"=>"TER3 Provider"} And a "circuit" exists with {"provider_name"=>"Another provider", "redacted_circuit_id"=>"ABC1", "provider_circuit_id"=>"C1", "circuit_type"=>CircuitType.find_by_name("Peering"), "service_type"=>CircuitServiceType.find_by_name("Dark Fiber"), :capacity => CircuitCapacity.find_by_name("1 Gbps"), "physical_wire_type"=>PhysicalWireType.find_by_name("Multi Mode Fiber"), "status"=> CircuitStatus.find_by_name("Cancelled"), "a_end"=>Site.find_by_identifier("TER1"), "b_end"=>Site.find_by_identifier("TER2")} And a "circuit" exists with {"provider_name"=>"Switch and Data", "redacted_circuit_id"=>"ABC2", "provider_circuit_id"=>"C2", "circuit_type"=>CircuitType.find_by_name("Backbone"), "service_type"=>CircuitServiceType.find_by_name("Dark Fiber"), :capacity => CircuitCapacity.find_by_name("1 Gbps"), "physical_wire_type"=>PhysicalWireType.find_by_name("Multi Mode Fiber"), "status"=> CircuitStatus.find_by_name("Cancelled"), "a_end"=>Site.find_by_identifier("TER1"), "b_end"=>Site.find_by_identifier("TER3")} When I am on the "connected_sites" page for site "TER1" Then the "connected-sites-list" should look like | Site ID | Site Name | Site Provider | Provider Circuit ID | Provider Name | Circuit Status | | TER2 | Somewhere2 | Some Provider | C1 | Another provider | Cancelled | | TER3 | Somewhere3 | TER3 Provider | C2 | Switch and Data | Cancelled | I am on the "connected_sites" page for site "TER2" Then the "connected-sites-list" should look like | Site ID | Site Name | Site Provider | Provider Circuit ID | Provider Name | Circuit Status | | TER1 | Somewhere1 | TER1 Provider | C1 | Another provider | Cancelled | When I am on the "connected_sites" page for site "TER3
http://www.elabs.se/blog/15-you-re-cuking-it-wrong
Worst. Scenario. Ever.
System Actors
Rule #3Identify and specialise your actors
Feature Story◇ As a [Specialised Actor]◇ I want [specific System Behavior]◇ So that I can [have a tangible benefit]
Feature: Talks ListingAs a LearnerI want to see abstracts of next meetup’s talksSo that I can see if I like any
Feature Story◇ As a [Specialised Actor]◇ I want [specific System Behavior]◇ So that I can [have a tangible benefit]
Feature: Talks ListingAs a LearnerI want to see abstracts of next meetup’s talksSo that I can see if I like any decide whether to attend the meetup
------------------------
Rule #4A feature must tell a valid story
Scenario: Successful reservation
Given I am on the "Book a place" screenWhen I enter "[email protected]" in "email" fieldAnd I enter "Joe" in "first_name" fieldAnd I enter "Bloggs" in "last_name" fieldAnd I click the "Reserve Now" buttonAnd I enter the displayed captcha in the “captcha” fieldThen a messagebox with green background pops upAnd the message "a place is reserved" appears in the messagebox
Scenario: Successful reservation
Given I am on the Reservation page
And I enter valid credentials
Then a place is reserved for me
Rule #5Features are about the ‘what’, not the ‘how’
Scenario: Session terminated
Given the session has ended
And the user has logged out
Then no more requests will be accepted by the server
???
session: A user session contains information about the user across multiple HTTP requests and is stored in a cookie
Rule #5Avoid ambiguous terms and speak the Actor’s language
Case study (original)Feature: Menu item highlighting
Scenario Outline: Menu shows current pageGiven I go to <any_page>Then the side menu should highlight the page I'm currently on
Examples: | any_page | | Home | | About | | Products |
Case study (modified)Feature: Navigation Link consistency
As the Design DirectorI want to the site to be navigated in the same way as the other company sites So that the company can maintain a consistent corporate image
Scenario Outline: Menu shows current pageGiven I go to <any_page>Then the side menu should highlight the page I'm currently on……
The colours of success Yellow
Everyone involved in writing features.
Cyan
Readable features.
Red
Behaviour discovery by specialised actors.
Black
Features must tell a valid story.
Purple
Unambiguous vocabulary.
CreditsSpecial thanks to all the people who made and released these awesome resources for free:
◇ Presentation template by SlidesCarnival◇ Photographs by Unsplash
Further reading
Thanks!Any questions?You can find me at:
◇ @FredAtBootstrap◇ [email protected]
Feature: Accident REST API
As a the visualiser web serviceI can access the accidents resource pageand retrieve relevant accident dataso that I can create accident occurrence visualisations on a map
Scenario: Get all accident dataGiven that there are 6 accident events in the databaseWhen I GET to "http://localhost:1337/accidents"Then I receive a JSON array with 6 objects in the response bodyAnd a status code of 200
Given(/^that there are (\d+) accident events in the database$/) do |no_of_accidents| rs = Situation.find(type: "accident") expect(rs.size).to eq(no_of_accidents.to_i)end
When(/^I GET to "([^"]*)"$/) do |page| @page = page res = Net::HTTP.get_response(URI.parse(@page)) @response_code = res.code.to_i @response = JSON.parse(res.body) expect(@response).not_to be nilend