The World of Tomorrow: Why You're Probably Wrong About Everything
BDD - you're doing it all wrong!
-
Upload
andrew-larcombe -
Category
Technology
-
view
231 -
download
1
Transcript of BDD - you're doing it all wrong!
Andrew Larcombe @andrewl
BDD? You’re doing it all wrong!
(perhaps)
Who am I?!Software Delivery Professional"Engineering: Drupal (nodejs, go-lang, solr, geospatial, ruby-on-rails, perl, c++)Process: Agile, Scrum, BDD"t: @andrewl w: andrewl.nete: [email protected]"
"
fluxus.io
"
"
What is Behavioural Driven Development?
Some common anti-patterns
“BDD is a second-generation, outside–in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology.”
(Dan North)
The Problem!We have complex communication problems, not technical problems (mostly)."Jargon, ‘Chinese Whispers’, early solutionising"Consequences: Locked in to delivering late, delayed or the wrong product, before we’ve even written a line of code.
“If I asked my customers what they wanted they would have said ‘a faster
horse’” (Henry Ford)
Behat
Requirement
Conversation
Discovery
Specification
Automation
For all, in a common language
Behat
BDD leads to Executable Specifications with Examples for features that deliver business value and that are written in
the domain language of the business!"
Behat is a tool for automating these specifications.!
Some BDD & Behat Antipatterns
"
All journeys sold between Brussels and Chicago with a child ticket should have at least one accompanying adult or senior
ticket.
As a user
I want to be prevented from purchasing a child only journey from Brussels to Chicago
So that…errr…???
Antipattern #1:“As a User”!
As the Company Lawyer
I want to prevent customers purchasing a child only ticket on flights from Brussels to Chicago
So that we’re compliant with regulations
This is the person that cares
This is why they care
Given I go to ‘/tickets.php’ And I select ‘0’ from ‘xpath://ticket-form/adults’And I select ‘2’ from ‘xpath://ticket-form/children’And I select ‘0’ from ‘xpath://ticket-form/youths’And I select ‘0’ from ‘xpath://ticket-form/seniors’And I click ‘xpath://ticket-form/submit’Then I should see “You cannot purchase child-only tickets for this journey” And I should be on ‘/tickets.php’
Antipattern #2:“Writing Brittle Tests not Specifications”!
Tight coupling with DOM
Tight coupling with URLsHard-coded messages?!?!!
Given I go to ‘/tickets.php’ And I select ‘0’ from ‘xpath://ticket-form/adults’And I select ‘2’ from ‘xpath://ticket-form/children’And I select ‘0’ from ‘xpath://ticket-form/youths’And I select ‘0’ from ‘xpath://ticket-form/seniors’And I click ‘xpath://ticket-form/submit’Then I should see “You cannot purchase child-only tickets for this journey” And I should be on ‘/tickets.php’
Repetition
Who even understands this??!?!!
Antipattern #2:“Writing Brittle Tests not Specifications”!
Given I am on the ticket search page When search for tickets from “<origin>” to “<destination>” for “<num_adults”> adults, “<num_children>” children and “<num_seniors> seniors Then I should see the child fare policy messageAnd be on the ticket search page
Examples: |origin |destination|num_adults|num_children|num_seniors||Brussels|Chicago |0 |1 |0 ||Brussels|Chicago |0 |2 |0 ||Brussels|Chicago |0 |3 |0 ||Brussels|Chicago |0 |4 |0 ||Brussels|Chicago |0 |5 |0 |
Page Objects!Separation of Concerns"Encapsulation"DRY (Don’t Repeat Yourself)"Hides implementation details"An API for the things you do on a page"e.g. class TicketSearchPage: it’s where you search for tickets (that’s what you do on the ticket search page)
§
class SearchPage
function search($origin, $dest, …) { $this->get(‘Search Form’) ->setOrigin($origin);
function warningMessage() { return $this->get
class SearchForm { function setOrigin($origin) { $this ->fillField(“From”, $origin); …etc…
class SearchContext { function iShouldSeePolicyMessage() { expect($this->getPage(‘search’)->warningMessage())->toBe(‘You cannot purchase child-only tickets for this journey’)
…Page Object Contexts
Hide the Complexity - Feature Contexts…
Page Objects…an approach!Start with wireframe/ui.""
Describe in English what you do on the page.""
Write a function in your Page object that maps onto a ‘real world’ action that you might perform on the page"eg search(), register(), uploadAnImage(), addAComment().""
Write a function in your Context that maps requirements into these actions and throws exceptions where required.""
Refactor, refactor, refactor
"
All journeys sold between Brussels and Capetown with 2 or more child tickets should
have at least one accompanying adult or senior ticket.
Given I am on the ticket search page When search for tickets from “<origin>” to “<destination>” for “<num_adults”> adults, “<num_children>” children and “<num_seniors> seniors Then I should see the child fare policy messageAnd be on the ticket search page
Examples: |origin |destination|num_adults|num_children|num_seniors||Brussels|Chicago |0 |1 |0 ||Brussels|Chicago |0 |2 |0 ||Brussels|Chicago |0 |3 |0 ||Brussels|Chicago |0 |4 |0 ||Brussels|Chicago |0 |5 |0 ||Brussels|Capetown |0 |2 |0 ||Brussels|Capetown |0 |3 |0 ||Brussels|Capetown |0 |4 |0 ||Brussels|Capetown |0 |5 |0 |
"
Add some front-end validation…after the user selects the origin and destination,
load the rules determining child ticket policies using AJAX
Given I go to ‘/tickets.php’ And I select ‘Brussels’ from ‘xpath://ticket-form/origin’ And I select ‘Chicago’ from ‘xpath://ticket-form/destination’ And I wait 3 seconds
Given I go to ‘/tickets.php’ And I select ‘Brussels’ from ‘xpath://ticket-form/origin’ And I select ‘Chicago’ from ‘xpath://ticket-form/destination’ And I wait 5 seconds
Never part of anyone’s specification, ever!
Antipattern #3:“And I wait…”!
public function spin ($lambda) { while (true) { try { if ($lambda($this)) { return true; } } catch (Exception $e) { //and do nothing here }
sleep(1); //wait and try again in a second } }
$this->spin(function($context) { $context->getSession()->getPage()->findById('adults'); });
"
Spin functions!
In review…not writing tests, discovering the specification
As a user
I want to be prevented from purchasing a child only journey from Brussels to Chicago
So that…errr…???
As the Company Lawyer
I want to prevent customers purchasing a child only ticket on flights from Brussels to Chicago
So that we’re compliant with regulations
Given I go to ‘/tickets.php’ And I select ‘0’ from ‘xpath://ticket-form/adults’And I select ‘2’ from ‘xpath://ticket-form/children’And I select ‘0’ from ‘xpath://ticket-form/youths’And I select ‘0’ from ‘xpath://ticket-form/seniors’And I click ‘xpath://ticket-form/submit’Then I should see “You cannot purchase child-only tickets for this journey” And I should be on ‘/tickets.php’
Given I am on the ticket search page When search for tickets from “<origin>” to “<destination>” for “<num_adults”> adults, “<num_children>” and “<num_seniors> seniors Then I should see the child fare policy messageAnd be on the ticket search page
Examples: |origin |destination|num_adults|num_children|num_seniors||Brussels|Chicago |0 |1 |0 ||Brussels|Chicago |0 |2 |0 ||Brussels|Chicago |0 |3 |0 ||Brussels|Chicago |0 |4 |0 ||Brussels|Chicago |0 |5 |0 ||Brussels|Capetown |0 |2 |0 ||Brussels|Capetown |0 |3 |0 ||Brussels|Capetown |0 |4 |0 ||Brussels|Capetown |0 |5 |0 |
Requirement
Conversation
Discovery
Specification
Automation
For all, in a common language
Behat
Links!Reading dannorth.net/introducing-bdddannorth.net/2010/08/30/introducing-deliberate-discoveryspecificationbyexample.com/key_ideas.html “Domain Driven Design” Eric Evans (domainlanguage.com) lizkeogh.com/2010/02/02/theyre-not-user-stories
Playingbehat.orgdrupal.org/project/drupalextensioncode.google.com/p/selenium/wiki/PageObjectsgithub.com/orangedigital/business-selector-extensiongithub.com/BossaConsulting/phpspec2-expect