BDD: Feature this! - Yolk Recruitment · SpecFlow (.NET) Lettuce (Python) JBehave ... Testing...

Post on 10-Jul-2018

221 views 0 download

Transcript of BDD: Feature this! - Yolk Recruitment · SpecFlow (.NET) Lettuce (Python) JBehave ... Testing...

BDD: Feature this!

Hello!I am Fred HeathYou can find me at

◇ @FredAtBootstrap◇ fred@bootstrap.me.uk

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

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 "joe@domain.com" 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◇ fred@bootstrap.me.uk

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