SlideShare a Scribd company logo
1 of 82
Download to read offline
OBJECT ORIENTED
BDD
with CUCUMBER
Thursday, October 3, 13
Who Am I?
Senior	
  So(ware	
  Engineer	
  at	
  New	
  Relic
20	
  years	
  of	
  web	
  applica9on	
  development
12	
  years	
  of	
  TDD
5	
  years	
  of	
  BDD
github.com/maFvanhorn	
  or	
  @nycplayer
Thursday, October 3, 13
New Relic CI
Thursday, October 3, 13
New Relic CI
Github,	
  TDDium,	
  Jenkins
Feature	
  branches,	
  Pull	
  Requests
Automa9c	
  builds,	
  Code	
  reviews
Automated	
  deploys,	
  but	
  some	
  manual	
  control
Thursday, October 3, 13
New Relic CI
We	
  deploy	
  3x	
  per	
  day
Automated	
  tes9ng	
  is	
  part	
  of	
  the	
  process
However...
Thursday, October 3, 13
New Relic CI
We	
  have	
  a	
  large,	
  slow	
  test	
  suite
We	
  have	
  a	
  large,	
  legacy	
  Rails	
  app
We	
  have	
  a	
  lack	
  of	
  up-­‐to-­‐date	
  documenta9on
We	
  o(en	
  have	
  communica9on	
  issues
Thursday, October 3, 13
New Relic CI
We	
  want	
  to	
  go	
  from	
  3x/day	
  to	
  ‘at	
  will’
We	
  are	
  dedica9ng	
  9me	
  to	
  improving	
  our	
  tests
Automated	
  acceptance	
  tests	
  are	
  key
(Faster	
  unit	
  tests	
  are	
  also	
  important)
Thursday, October 3, 13
Behavior
Driven
development
Thursday, October 3, 13
Behavior
Driven
development
BDD	
  is	
  a	
  second-­‐genera9on,	
  outside–in,	
  pull-­‐based,	
  mul9ple-­‐
stakeholder,	
  mul9ple-­‐scale,	
  high-­‐automa9on,	
  agile	
  methodology.	
  
It	
  describes	
  a	
  cycle	
  of	
  interac9ons	
  with	
  well-­‐defined	
  outputs,	
  
resul9ng	
  in	
  the	
  delivery	
  of	
  working,	
  tested	
  so(ware	
  that	
  maFers.
-­‐	
  Dan	
  North
Thursday, October 3, 13
Behavior
Driven
Development
“BDD	
  describes	
  TDD	
  done	
  well”
-­‐	
  MaF	
  Wynne
Thursday, October 3, 13
Behavior
Driven
Development
“Can	
  you	
  give	
  me	
  some	
  examples	
  (of	
  using	
  it)?”
vs.
“What	
  are	
  the	
  requirements	
  (for	
  implemen9ng	
  it)?”
Thursday, October 3, 13
Outside In
Start	
  with	
  a	
  conversa9on
Determine	
  the	
  business	
  value
Provide	
  examples	
  of	
  use
Thursday, October 3, 13
Outside In
	
  User	
  Interface
Browser
Views
Controllers
Models
Thursday, October 3, 13
Outside In
	
  User	
  Interface
Browser
Views
Controllers
Models
Cucumber
RSpec
Thursday, October 3, 13
Outside In
Red,	
  Green,	
  REFACTOR
Outer	
  loop:	
  Features,	
  
stories,	
  scenarios
Inner	
  loop:	
  Unit	
  tests,	
  
classes,	
  methods
Cucumber
Thursday, October 3, 13
Red,	
  Green,	
  REFACTOR
Outer	
  loop:	
  Features,	
  
stories,	
  scenarios
Inner	
  loop:	
  Unit	
  tests,	
  
classes,	
  methods
Outside In Cucumber
RSpec
Thursday, October 3, 13
Outside In Cucumber
RSpecRed,	
  Green,	
  REFACTOR
Outer	
  loop:	
  Features,	
  
stories,	
  scenarios
Inner	
  loop:	
  Unit	
  tests,	
  
classes,	
  methods
Thursday, October 3, 13
Outside In Cucumber
RSpecRed,	
  Green,	
  REFACTOR
Outer	
  loop:	
  Features,	
  
stories,	
  scenarios
Inner	
  loop:	
  Unit	
  tests,	
  
classes,	
  methods
Thursday, October 3, 13
BDD TOOLS
Cucumber,	
  RSpec,	
  FitNesse
Gherkin
Spinach,	
  Turnip,	
  Steak,	
  Filet
Capybara,	
  Wa9r,	
  WebRAT
Selenium,	
  Webkit,	
  PhantomJS,	
  Rack::Test
Thursday, October 3, 13
Cucumber Complaints
Don’t	
  need	
  English,	
  code	
  is	
  fine
Doesn’t	
  save	
  developer	
  9me
BriFle	
  tests,	
  needing	
  constant	
  maintenance
Thursday, October 3, 13
You’re
DoING IT
WRONG
Thursday, October 3, 13
Cucumber Done right
Minimizes	
  miscommunica9on
Hides	
  implementa9on	
  details
Provides	
  robust	
  regression	
  tests
Communicates	
  inten9ons
Thursday, October 3, 13
Cucumber Done right
Cucumber	
  allows	
  us	
  to	
  inform,	
  in	
  plain	
  English,	
  the	
  
intended	
  behavior	
  of	
  applica9ons	
  we	
  build	
  to	
  future	
  
developers,	
  rather	
  than	
  forcing	
  them	
  to	
  spelunk	
  
through	
  code	
  to	
  figure	
  it	
  out.
-­‐	
  Ma,	
  Polito
Thursday, October 3, 13
Object ORiented
Cucumber
Thursday, October 3, 13
Object ORiented
Cucumber
Keep	
  data	
  and	
  behavior	
  together
Hide	
  implementa9on	
  details
Send	
  messages	
  to	
  accomplish	
  tasks
Thursday, October 3, 13
Page Object
URLs
UI Elements
Page Sections
Domain
Action
Methods
Browser
Driver
Thursday, October 3, 13
Page Object
Provides	
  a	
  model	
  for	
  a	
  web	
  UI
Hides	
  details	
  of	
  dealing	
  with	
  browser
Keeps	
  UI	
  details	
  in	
  one	
  place
Enables	
  expressive	
  test	
  code
Thursday, October 3, 13
Site Prism
Open	
  source	
  Ruby	
  gem	
  
Provides	
  simple	
  DSL	
  for	
  page	
  Objects
Exposes	
  Capybara	
  nodes
Thursday, October 3, 13
Technique
Plain	
  English,	
  not	
  code	
  (or	
  pseudo-­‐code)
Domain	
  concepts,	
  not	
  implementa9on	
  details
Focus	
  on	
  the	
  value,	
  not	
  the	
  incidentals
Thursday, October 3, 13
Stories & Scenarios
Impera9ve
Scenario: Typical Meetup
Given I am on the estimate page
When I fill in "Guest count" with "10"
And I fill in "Slice count" with "2"
And I press "Get Estimate"
Then I should see "You will need to order 3 pizzas"
Thursday, October 3, 13
“English	
  -­‐	
  we	
  hateses	
  it”
Scenario: Typical Meetup
Given I am on “/estimates/new”
And I fill in "input#guests" with "10"
And I fill in "input#slices" with "2"
And I press "input[type=’submit’]"
Then I should see "You will need to order 3 pizzas"
Stories & Scenarios
Thursday, October 3, 13
Stories & Scenarios
Declara9ve
Scenario: Typical Meetup (Guests eat 2 slices each)
Given There are 10 guests expected
When I ask how much to order
Then I will know I need to buy 3 pizzas
Thursday, October 3, 13
Examples
Feature: Estimating Pizza Requirements
In order to avoid wasting either pizza or money
As an organizer
I want to know how many pizzas I need to order
Background:
Given there are 10 guests expected
Scenario: Typical meetup (Guests eat 2 slices)
Given the guests are hungry
When I ask how much to order
Then I will know I need to buy 3 pizzas
Scenario: Late-night meetup (Guests eat 3 slices)
Given the guests are starving
When I ask how much to order
Then I will know I need to buy 4 pizzas
Scenario: After-lunch meetup (Guests eat 1 slice)
Given the guests are full
When I ask how much to order
Then I will know I need to buy 2 pizzas
Thursday, October 3, 13
StepDefinitions
Use	
  methods	
  that	
  relate	
  to	
  the	
  domain
Avoid	
  nes9ng	
  steps
Mostly	
  black	
  box
Some	
  white	
  box	
  can	
  be	
  very	
  useful
Thursday, October 3, 13
Examples
Given(/^there are (d+) guests expected$/) do |guest_count|
Site.new_estimate_page.guests_expected = guest_count
end
Given(/^the guests are (full|hungry|starving)$/) do |hunger_level|
Site.new_estimate_page.hunger_level = hunger_level
end
When 'I ask how much to order' do
Site.new_estimate_page.request_estimate
end
Then(/^I will know I need to buy (d+ pizzas)$/) do |pie_count|
expect(Site.new_estimate_page).to have_text("#{pie_count}")
end
Thursday, October 3, 13
Examples
Given(/^there are (d+) guests expected$/) do |guest_count|
Site.new_estimate_page.guests_expected = guest_count
end
Given(/^the guests are (full|hungry|starving)$/) do |hunger_level|
Site.new_estimate_page.hunger_level = hunger_level
end
When 'I ask how much to order' do
Site.new_estimate_page.request_estimate
end
Then(/^I will know I need to buy (d+ pizzas)$/) do |pie_count|
expect(Site.new_estimate_page).to have_text("#{pie_count}")
end
Thursday, October 3, 13
Examples
# Utility class to provide easy access to page objects.
class Site
def self.current_page
@current_page
end
def self.method_missing(meth_name, *args)
klass = meth_name.to_s.classify
@current_page = klass.constantize.new
end
end
Thursday, October 3, 13
Examples
class NewEstimatePage < SitePrism::Page
URL = Rails.application.routes.url_helpers.root_path
set_url URL
set_url_matcher %r(#{URL})
element :guests_field, "input[name='estimate[guest_count]']"
element :slices_field, "input[name='estimate[slice_count]']"
element :submit_btn, "input[name='commit']"
# ... instance methods elided ...
end
Thursday, October 3, 13
Examples
class NewEstimatePage < SitePrism::Page
URL = Rails.application.routes.url_helpers.root_path
set_url URL
set_url_matcher %r(#{URL})
element :guests_field, "input[name='estimate[guest_count]']"
element :slices_field, "input[name='estimate[slice_count]']"
element :submit_btn, "input[name='commit']"
# ... instance methods elided ...
end
Thursday, October 3, 13
Examples
class NewEstimatePage < SitePrism::Page
URL = Rails.application.routes.url_helpers.root_path
set_url URL
set_url_matcher %r(#{URL})
element :guests_field, "input[name='estimate[guest_count]']"
element :slices_field, "input[name='estimate[slice_count]']"
element :submit_btn, "input[name='commit']"
# ... instance methods elided ...
end
Thursday, October 3, 13
Examplesclass NewEstimatePage < SitePrism::Page
# ... DSL elided ...
def guests_expected=(guest_count)
load unless displayed?
guests_field.set guest_count
end
def hunger_level=(hunger)
load unless displayed?
slices_per_person = case hunger
when 'full' then 1
when 'hungry' then 2
when 'starving' then 3
end
slices_field.set slices_per_person
end
def request_estimate
load unless displayed?
submit_btn.click
end
end
Thursday, October 3, 13
DEMO
Thursday, October 3, 13
DEMO
Thursday, October 3, 13
Changes
Thursday, October 3, 13
Product Manager:
“We	
  should	
  es9mate	
  beer	
  as	
  well”
“It	
  should	
  work	
  the	
  same	
  way	
  as	
  pizza”
Thursday, October 3, 13
Application Changes:
Change	
  es9mate	
  model
Change	
  form	
  view
Change	
  es9mate	
  view
Change	
  es9mate	
  view	
  helper
Thursday, October 3, 13
Cucumber Changes:
Change	
  scenarios
Add	
  steps	
  for	
  new	
  scenario	
  changes
Add	
  elements	
  to	
  page	
  model
Add	
  methods	
  to	
  page	
  model	
  to	
  use	
  elements
Thursday, October 3, 13
Examples
Scenario: Typical meetup
Given the guests are hungry
And the guests love beer
When I ask how much to order
Then I will know I need to buy 3 pizza pies
And I will know I need to buy 1 case and 1 six-pack of beer
Scenario: Late-night meetup
Given the guests are starving
And the guests like beer
When I ask how much to order
Then I will know I need to buy 4 pizza pies
And I will know I need to buy 1 case of beer
Scenario: After-lunch meetup
Given the guests are full
And the guests are underage
When I ask how much to order
Then I will know I need to buy 2 pizza pies
And I will know I don't need to buy beer
Thursday, October 3, 13
Examples
Given(/^the guests (like|love) beer$/) do |thirst|
Site.new_estimate_page.thirst_level = thirst
end
Given(/^the guests are underage$/) do
Site.new_estimate_page.thirst_level = 'none'
end
Then(/^I will know I need to buy ((?:d+ cases?)?(?: and )?(?:d+ six-packs?)? of beer)$/) do |content|
expect(Site.new_estimate_page).to have_text(content)
end
Then(/^I will know I don't need to buy beer$/) do
expect(Site.new_estimate_page).to have_text("no beer")
end
Thursday, October 3, 13
Examples
class NewEstimatePage < SitePrism::Page
# ... URL matchers elided ...
element :guests_field, "input[name='estimate[guest_count]']"
element :slices_field, "input[name='estimate[slice_count]']"
element :beers_field, "input[name='estimate[beer_count]']"
element :submit_btn, "input[name='commit']"
# ... other methods elided ...
def thirst_level=(thirst)
load unless displayed?
beer_count = case thirst
when 'none' then 0
when 'like' then 2
when 'love' then 3
end
beers_field.set beer_count
end
end
Thursday, October 3, 13
Examples
Thursday, October 3, 13
Examples
Thursday, October 3, 13
Refactor
Thursday, October 3, 13
Examples
Given(/^there are (d+) guests expected$/) do |guest_count|
Site.new_estimate_page.guests_expected = guest_count
end
Given(/^the guests are (full|hungry|starving)$/) do |hunger_level|
Site.new_estimate_page.hunger_level = hunger_level
end
When 'I ask how much to order' do
Site.new_estimate_page.request_estimate
end
Then(/^I will know I need to buy (d+ pizza pies)$/) do |pie_count|
expect(Site.new_estimate_page).to have_text("#{pie_count}")
end
Thursday, October 3, 13
HELPER Modules
Helpers	
  are	
  glue	
  between	
  inten9on	
  and	
  
implementa9on	
  
Swapping	
  out	
  helpers	
  can	
  adapt	
  your	
  suite	
  to	
  
different	
  plajorms	
  or	
  devices
Page	
  Objects	
  are	
  for	
  page	
  based	
  UIs,	
  but	
  the	
  
principles	
  can	
  be	
  applied	
  to	
  other	
  domains
Thursday, October 3, 13
Examples
module WebHelper
def guests_expected count
Site.new_estimate_page.guests_expected = count
end
def general_hunger_level hunger
Site.new_estimate_page.hunger_level = hunger
end
def general_thirst_level thirst
Site.new_estimate_page.thirst_level = thirst
end
def submit_request_for_estimate
Site.new_estimate_page.request_estimate
end
def verify_pizzas_needed num_pies
expect(Site.new_estimate_page).to have_text("#{num_pies} pizza pies")
end
def verify_beer_needed beer_text
expect(Site.new_estimate_page).to have_text(beer_text)
end
end
World(WebHelper)
Thursday, October 3, 13
ExamplesTransform /(d+)/ do |num|
num.to_i
end
Given /^there are (d+) guests expected$/ do |guest_count|
guests_expected guest_count
end
Given /^the guests are (full|hungry|starving)$/ do |hunger|
general_hunger_level hunger
end
Given /^the guests (like|love) beer$/ do |thirst|
general_thirst_level thirst
end
When 'I ask how much to order' do
submit_request_for_estimate
end
Then(/^I will know I need to buy (d+) pizza pies$/) do |pie_count|
verify_pizzas_needed pie_count
end
Then(/^I will know I need to buy ((?:d+ cases?)?(?: and )?(?:d+ six-packs?)? of beer)
$/) do |beer_text|
verify_beer_needed beer_text
end
Thursday, October 3, 13
Product Manager:
“It’s	
  too	
  easy	
  to	
  make	
  typos.”
“Last	
  week	
  Ted	
  ordered	
  33	
  beers	
  per	
  person.”
“The	
  carpet	
  is	
  s9ll	
  not	
  completely	
  clean.”
Thursday, October 3, 13
Application Changes:
Change	
  form	
  view	
  to	
  use	
  different	
  widgets
Thursday, October 3, 13
Cucumber Changes:
Update	
  page	
  object	
  to	
  use	
  new	
  elements
Thursday, October 3, 13
Examples
element :slices_field, "input[name='estimate[slice_count]']"
element :beers_field, "input[name='estimate[beer_count]']"
def hunger_level=(hunger)
load unless displayed?
slices_per_person = case hunger
when 'full' then 1
when 'hungry' then 2
when 'starving' then 3
end
slices_field.set slices_per_person
end
def thirst_level=(thirst)
load unless displayed?
beer_count = case thirst
when 'none' then 0
when 'like' then 2
when 'love' then 3
end
beers_field.set beer_count
end
Thursday, October 3, 13
Examples
class NewEstimatePage < SitePrism::Page
element :hunger_select, "select[name='estimate[slice_count]']"
element :thirst_select, "select[name='estimate[beer_count]']"
def hunger_level=(hunger)
load unless displayed?
hunger_select.select hunger
end
def thirst_level=(thirst)
load unless displayed?
thirst_select.select case thirst
when 'like' then 'thirsty'
when 'love' then 'extremely thirsty'
else 'none'
end
end
end
Thursday, October 3, 13
Examples
Thursday, October 3, 13
MORE Changes
Thursday, October 3, 13
Product Manager:
“We’re	
  adding	
  a	
  registra9on	
  feature.”
“Entering	
  the	
  number	
  of	
  guests	
  is	
  redundant.”
“We’ll	
  count	
  the	
  guests	
  in	
  the	
  database.”
Thursday, October 3, 13
Application Changes:
Create	
  Guest	
  model,	
  with	
  db	
  migra9on
Add	
  guest	
  list	
  view	
  with	
  add	
  guest	
  form
Add	
  guests	
  controller
Change	
  routes	
  to	
  add	
  guest	
  routes
Change	
  es9mate	
  form	
  view
Change	
  es9mate	
  controller
Thursday, October 3, 13
Cucumber Changes:
Change	
  the	
  step	
  that	
  sets	
  up	
  the	
  number	
  of	
  
guests.
Thursday, October 3, 13
Examples
Given /^there are (d+) guests expected$/ do |guest_count|
guests_expected guest_count
end
Thursday, October 3, 13
Examples
Given /^there are (d+) guests expected$/ do |guest_count|
guest_count.times{ Fabricate(:guest) }
end
Thursday, October 3, 13
Alternative
Change	
  the	
  implementa9on	
  of	
  the	
  method	
  
the	
  step	
  calls.
Thursday, October 3, 13
Alternative
def guests_expected guest_count
Site.new_estimate_page.guests_expected = count
end
Thursday, October 3, 13
Alternative
def guests_expected guest_count
guest_count.times{ Fabricate(:guest) }
end
Thursday, October 3, 13
Alternative
module DatabaseHelper
def guests_expected guest_count
guest_count.times{ Fabricate(:guest) }
end
end
Thursday, October 3, 13
Alternative
# support/helpers/database_helper.rb
module DatabaseHelper
def guests_expected guest_count
guest_count.times{ Fabricate(:guest) }
end
end
# support/helpers/helper_setup.rb
require_relative 'web_helper'
require_relative 'database_helper'
World(WebHelper)
World(DatabaseHelper)
Thursday, October 3, 13
Examples
Thursday, October 3, 13
Examples
Thursday, October 3, 13
Examples
Thursday, October 3, 13
platform changes
Thursday, October 3, 13
Examplesmodule PersonalAssistantHelper
def general_hunger_level hunger
PersonalAssistant.tell "Guests will be #{hunger}"
end
def general_thirst_level thirst
PersonalAssistant.tell "Guests will #{thirst} beer" unless thirst == 'none'
end
def submit_request_for_estimate
PersonalAssistant.ask "How much do I need?"
end
def verify_pizzas_needed num_pies
expect(PersonalAssistant.guess_pizza).to eq(num_pies)
end
def verify_beer_needed beer_text
expect(PersonalAssistant.guess_beer).to eq(beer_text)
end
end
Thursday, October 3, 13
SUMMARY
Keep	
  implementa9on	
  details	
  in	
  one	
  place
Use	
  objects	
  to	
  model	
  the	
  system
Use	
  abstrac9on	
  levels	
  to	
  scope	
  changes
Express	
  your	
  intent	
  throughout	
  the	
  code
Thursday, October 3, 13
QUESTIONS?
Thursday, October 3, 13
RESOURCES
Source	
  Code:
github.com/maFvanhorn/pizza_beer
github.com/natritmeyer/site_prism
Further	
  Reading:
mar9nfowler.com/bliki/PageObject.html
blog.maFwynne.net/2012/11/20/tdd-­‐vs-­‐bdd
dannorth.net/2012/05/31/bdd-­‐is-­‐like-­‐tdd-­‐if
www.elabs.se/blog/15-­‐you-­‐re-­‐cuking-­‐it-­‐wrong
gojko.net/2013/09/30/wri9ng-­‐as-­‐a-­‐user-­‐does-­‐not-­‐make-­‐it-­‐a-­‐user-­‐story
Contact	
  Me:
web:	
  maFvanhorn.com
github:	
  maFvanhorn
twiFer:	
  @nycplayer
email:	
  mvanhorn@newrelic	
  or	
  maFvanhorn@gmail.com
Thursday, October 3, 13

More Related Content

Viewers also liked

ATAAS 2016 - Amol pradhan - Bridging the gap between business and technology ...
ATAAS 2016 - Amol pradhan - Bridging the gap between business and technology ...ATAAS 2016 - Amol pradhan - Bridging the gap between business and technology ...
ATAAS 2016 - Amol pradhan - Bridging the gap between business and technology ...Agile Testing Alliance
 
Bdd for legacy system
Bdd for legacy systemBdd for legacy system
Bdd for legacy systemSpin Lai
 
Advanced Ruby Idioms So Clean You Can Eat Off Of Them
Advanced Ruby Idioms So Clean You Can Eat Off Of ThemAdvanced Ruby Idioms So Clean You Can Eat Off Of Them
Advanced Ruby Idioms So Clean You Can Eat Off Of ThemBrian Guthrie
 
10 things about BDD, Cucumber and SpecFlow - Long Version 2016
10 things about BDD, Cucumber and SpecFlow - Long Version 201610 things about BDD, Cucumber and SpecFlow - Long Version 2016
10 things about BDD, Cucumber and SpecFlow - Long Version 2016Seb Rose
 
BDD and Test Automation in Evalutionary Product Suite
BDD and Test Automation in Evalutionary Product SuiteBDD and Test Automation in Evalutionary Product Suite
BDD and Test Automation in Evalutionary Product SuiteLasantha Ranaweera
 
Mock Aren't Stub 讀後心得
Mock Aren't Stub 讀後心得Mock Aren't Stub 讀後心得
Mock Aren't Stub 讀後心得Wei Jen Lu
 
Impact Maps/Story Maps - liefern was wirklich zählt
Impact Maps/Story Maps - liefern was wirklich zähltImpact Maps/Story Maps - liefern was wirklich zählt
Impact Maps/Story Maps - liefern was wirklich zähltChristian Hassa
 
Scaffolding a legacy app with BDD scenarios using SpecFlow/Cucumber (BDD Lond...
Scaffolding a legacy app with BDD scenarios using SpecFlow/Cucumber (BDD Lond...Scaffolding a legacy app with BDD scenarios using SpecFlow/Cucumber (BDD Lond...
Scaffolding a legacy app with BDD scenarios using SpecFlow/Cucumber (BDD Lond...Gáspár Nagy
 
Moving away from legacy code (AgileCymru)
Moving away from legacy code  (AgileCymru)Moving away from legacy code  (AgileCymru)
Moving away from legacy code (AgileCymru)Konstantin Kudryashov
 
Impact Mapping with Innovation Games (R)
Impact Mapping with Innovation Games (R)Impact Mapping with Innovation Games (R)
Impact Mapping with Innovation Games (R)Christian Hassa
 
Cross mobile testautomation mit Xamarin & SpecFlow
Cross mobile testautomation mit Xamarin & SpecFlowCross mobile testautomation mit Xamarin & SpecFlow
Cross mobile testautomation mit Xamarin & SpecFlowChristian Hassa
 
Moving away from legacy code with BDD
Moving away from legacy code with BDDMoving away from legacy code with BDD
Moving away from legacy code with BDDKonstantin Kudryashov
 
Impact Mapping with Innovation Games (TM)
Impact Mapping with Innovation Games (TM)Impact Mapping with Innovation Games (TM)
Impact Mapping with Innovation Games (TM)Christian Hassa
 

Viewers also liked (18)

ATAAS 2016 - Amol pradhan - Bridging the gap between business and technology ...
ATAAS 2016 - Amol pradhan - Bridging the gap between business and technology ...ATAAS 2016 - Amol pradhan - Bridging the gap between business and technology ...
ATAAS 2016 - Amol pradhan - Bridging the gap between business and technology ...
 
Bdd for legacy system
Bdd for legacy systemBdd for legacy system
Bdd for legacy system
 
Ruby object model
Ruby object modelRuby object model
Ruby object model
 
Advanced Ruby Idioms So Clean You Can Eat Off Of Them
Advanced Ruby Idioms So Clean You Can Eat Off Of ThemAdvanced Ruby Idioms So Clean You Can Eat Off Of Them
Advanced Ruby Idioms So Clean You Can Eat Off Of Them
 
Impact Map Your Project
Impact Map Your ProjectImpact Map Your Project
Impact Map Your Project
 
10 things about BDD, Cucumber and SpecFlow - Long Version 2016
10 things about BDD, Cucumber and SpecFlow - Long Version 201610 things about BDD, Cucumber and SpecFlow - Long Version 2016
10 things about BDD, Cucumber and SpecFlow - Long Version 2016
 
BDD and Test Automation in Evalutionary Product Suite
BDD and Test Automation in Evalutionary Product SuiteBDD and Test Automation in Evalutionary Product Suite
BDD and Test Automation in Evalutionary Product Suite
 
BDD com Cucumber
BDD com CucumberBDD com Cucumber
BDD com Cucumber
 
Mock Aren't Stub 讀後心得
Mock Aren't Stub 讀後心得Mock Aren't Stub 讀後心得
Mock Aren't Stub 讀後心得
 
Impact Maps/Story Maps - liefern was wirklich zählt
Impact Maps/Story Maps - liefern was wirklich zähltImpact Maps/Story Maps - liefern was wirklich zählt
Impact Maps/Story Maps - liefern was wirklich zählt
 
Upcoming events 2017
Upcoming events 2017Upcoming events 2017
Upcoming events 2017
 
Scaffolding a legacy app with BDD scenarios using SpecFlow/Cucumber (BDD Lond...
Scaffolding a legacy app with BDD scenarios using SpecFlow/Cucumber (BDD Lond...Scaffolding a legacy app with BDD scenarios using SpecFlow/Cucumber (BDD Lond...
Scaffolding a legacy app with BDD scenarios using SpecFlow/Cucumber (BDD Lond...
 
Moving away from legacy code (AgileCymru)
Moving away from legacy code  (AgileCymru)Moving away from legacy code  (AgileCymru)
Moving away from legacy code (AgileCymru)
 
Help! My Legacy Application is Unmaintainable!
Help! My Legacy Application is Unmaintainable!Help! My Legacy Application is Unmaintainable!
Help! My Legacy Application is Unmaintainable!
 
Impact Mapping with Innovation Games (R)
Impact Mapping with Innovation Games (R)Impact Mapping with Innovation Games (R)
Impact Mapping with Innovation Games (R)
 
Cross mobile testautomation mit Xamarin & SpecFlow
Cross mobile testautomation mit Xamarin & SpecFlowCross mobile testautomation mit Xamarin & SpecFlow
Cross mobile testautomation mit Xamarin & SpecFlow
 
Moving away from legacy code with BDD
Moving away from legacy code with BDDMoving away from legacy code with BDD
Moving away from legacy code with BDD
 
Impact Mapping with Innovation Games (TM)
Impact Mapping with Innovation Games (TM)Impact Mapping with Innovation Games (TM)
Impact Mapping with Innovation Games (TM)
 

Similar to Object-Oriented BDD w/ Cucumber by Matt van Horn

Cooking an Omelette with Chef
Cooking an Omelette with ChefCooking an Omelette with Chef
Cooking an Omelette with Chefctaintor
 
A Big Look at MiniTest
A Big Look at MiniTestA Big Look at MiniTest
A Big Look at MiniTestMark
 
Feature Flagging your Infrastructure for Fun and Profit
Feature Flagging your Infrastructure for Fun and ProfitFeature Flagging your Infrastructure for Fun and Profit
Feature Flagging your Infrastructure for Fun and ProfitDaniel Schauenberg
 
Specking Interactors with PHPSpec and YOLO (DDD) at PHPConference Argentina 2013
Specking Interactors with PHPSpec and YOLO (DDD) at PHPConference Argentina 2013Specking Interactors with PHPSpec and YOLO (DDD) at PHPConference Argentina 2013
Specking Interactors with PHPSpec and YOLO (DDD) at PHPConference Argentina 2013cordoval
 
Team Calendars and Confluence New Features, Ryan Anderson, Atlassian
Team Calendars and Confluence New Features, Ryan Anderson, AtlassianTeam Calendars and Confluence New Features, Ryan Anderson, Atlassian
Team Calendars and Confluence New Features, Ryan Anderson, AtlassianAtlassian
 
Infrastructure as Data - PuppetConf 2013
Infrastructure as Data - PuppetConf 2013Infrastructure as Data - PuppetConf 2013
Infrastructure as Data - PuppetConf 2013Puppet
 
A Big Look at MiniTest
A Big Look at MiniTestA Big Look at MiniTest
A Big Look at MiniTestMark
 
Become Master of Your Own Universe - DIBI 2013
Become Master of Your Own Universe - DIBI 2013Become Master of Your Own Universe - DIBI 2013
Become Master of Your Own Universe - DIBI 2013Phil Sturgeon
 
Taming Pythons with ZooKeeper
Taming Pythons with ZooKeeperTaming Pythons with ZooKeeper
Taming Pythons with ZooKeeperJyrki Pulliainen
 
Distributed percolator in elasticsearch
Distributed percolator in elasticsearchDistributed percolator in elasticsearch
Distributed percolator in elasticsearchmartijnvg
 
DIY Synthetic: Private WebPagetest Magic
DIY Synthetic: Private WebPagetest MagicDIY Synthetic: Private WebPagetest Magic
DIY Synthetic: Private WebPagetest MagicJonathan Klein
 
Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013
Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013
Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013Mike Desjardins
 
Unit testing like a pirate #wceu 2013
Unit testing like a pirate #wceu 2013Unit testing like a pirate #wceu 2013
Unit testing like a pirate #wceu 2013Ptah Dunbar
 
실시간 웹 협업도구 만들기 V0.3
실시간 웹 협업도구 만들기 V0.3실시간 웹 협업도구 만들기 V0.3
실시간 웹 협업도구 만들기 V0.3NAVER D2
 
App to App: Design and Surface Local APIs
App to App: Design and Surface Local APIsApp to App: Design and Surface Local APIs
App to App: Design and Surface Local APIsTy Smith
 
Using Orchestration in Puppet Enterprise 3 - PuppetConf 2013
Using Orchestration in Puppet Enterprise 3 - PuppetConf 2013Using Orchestration in Puppet Enterprise 3 - PuppetConf 2013
Using Orchestration in Puppet Enterprise 3 - PuppetConf 2013Puppet
 
CPANci: Continuous Integration for CPAN
CPANci: Continuous Integration for CPANCPANci: Continuous Integration for CPAN
CPANci: Continuous Integration for CPANMike Friedman
 

Similar to Object-Oriented BDD w/ Cucumber by Matt van Horn (19)

Cooking an Omelette with Chef
Cooking an Omelette with ChefCooking an Omelette with Chef
Cooking an Omelette with Chef
 
A Big Look at MiniTest
A Big Look at MiniTestA Big Look at MiniTest
A Big Look at MiniTest
 
Feature Flagging your Infrastructure for Fun and Profit
Feature Flagging your Infrastructure for Fun and ProfitFeature Flagging your Infrastructure for Fun and Profit
Feature Flagging your Infrastructure for Fun and Profit
 
Specking Interactors with PHPSpec and YOLO (DDD) at PHPConference Argentina 2013
Specking Interactors with PHPSpec and YOLO (DDD) at PHPConference Argentina 2013Specking Interactors with PHPSpec and YOLO (DDD) at PHPConference Argentina 2013
Specking Interactors with PHPSpec and YOLO (DDD) at PHPConference Argentina 2013
 
Team Calendars and Confluence New Features, Ryan Anderson, Atlassian
Team Calendars and Confluence New Features, Ryan Anderson, AtlassianTeam Calendars and Confluence New Features, Ryan Anderson, Atlassian
Team Calendars and Confluence New Features, Ryan Anderson, Atlassian
 
Infrastructure as Data - PuppetConf 2013
Infrastructure as Data - PuppetConf 2013Infrastructure as Data - PuppetConf 2013
Infrastructure as Data - PuppetConf 2013
 
A Big Look at MiniTest
A Big Look at MiniTestA Big Look at MiniTest
A Big Look at MiniTest
 
Become Master of Your Own Universe - DIBI 2013
Become Master of Your Own Universe - DIBI 2013Become Master of Your Own Universe - DIBI 2013
Become Master of Your Own Universe - DIBI 2013
 
Scaling Deployment at Etsy
Scaling Deployment at EtsyScaling Deployment at Etsy
Scaling Deployment at Etsy
 
Taming Pythons with ZooKeeper
Taming Pythons with ZooKeeperTaming Pythons with ZooKeeper
Taming Pythons with ZooKeeper
 
Distributed percolator in elasticsearch
Distributed percolator in elasticsearchDistributed percolator in elasticsearch
Distributed percolator in elasticsearch
 
DIY Synthetic: Private WebPagetest Magic
DIY Synthetic: Private WebPagetest MagicDIY Synthetic: Private WebPagetest Magic
DIY Synthetic: Private WebPagetest Magic
 
Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013
Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013
Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013
 
Unit testing like a pirate #wceu 2013
Unit testing like a pirate #wceu 2013Unit testing like a pirate #wceu 2013
Unit testing like a pirate #wceu 2013
 
실시간 웹 협업도구 만들기 V0.3
실시간 웹 협업도구 만들기 V0.3실시간 웹 협업도구 만들기 V0.3
실시간 웹 협업도구 만들기 V0.3
 
Storyplayer
StoryplayerStoryplayer
Storyplayer
 
App to App: Design and Surface Local APIs
App to App: Design and Surface Local APIsApp to App: Design and Surface Local APIs
App to App: Design and Surface Local APIs
 
Using Orchestration in Puppet Enterprise 3 - PuppetConf 2013
Using Orchestration in Puppet Enterprise 3 - PuppetConf 2013Using Orchestration in Puppet Enterprise 3 - PuppetConf 2013
Using Orchestration in Puppet Enterprise 3 - PuppetConf 2013
 
CPANci: Continuous Integration for CPAN
CPANci: Continuous Integration for CPANCPANci: Continuous Integration for CPAN
CPANci: Continuous Integration for CPAN
 

More from Solano Labs

Constant Contact SF's Road to CD
Constant Contact SF's Road to CDConstant Contact SF's Road to CD
Constant Contact SF's Road to CDSolano Labs
 
Testing sad-paths
Testing sad-pathsTesting sad-paths
Testing sad-pathsSolano Labs
 
Why Software Test Performance Matters
Why Software Test Performance MattersWhy Software Test Performance Matters
Why Software Test Performance MattersSolano Labs
 
The 10 Commandments of Release Engineering
The 10 Commandments of Release EngineeringThe 10 Commandments of Release Engineering
The 10 Commandments of Release EngineeringSolano Labs
 
Don't hate, automate. lessons learned from implementing continuous delivery
Don't hate, automate. lessons learned from implementing continuous deliveryDon't hate, automate. lessons learned from implementing continuous delivery
Don't hate, automate. lessons learned from implementing continuous deliverySolano Labs
 
Boston MeetUp 10.10
Boston MeetUp 10.10Boston MeetUp 10.10
Boston MeetUp 10.10Solano Labs
 
Automated testing san francisco oct 2013
Automated testing san francisco oct 2013Automated testing san francisco oct 2013
Automated testing san francisco oct 2013Solano Labs
 

More from Solano Labs (8)

Constant Contact SF's Road to CD
Constant Contact SF's Road to CDConstant Contact SF's Road to CD
Constant Contact SF's Road to CD
 
Testing sad-paths
Testing sad-pathsTesting sad-paths
Testing sad-paths
 
Why Software Test Performance Matters
Why Software Test Performance MattersWhy Software Test Performance Matters
Why Software Test Performance Matters
 
The 10 Commandments of Release Engineering
The 10 Commandments of Release EngineeringThe 10 Commandments of Release Engineering
The 10 Commandments of Release Engineering
 
Don't hate, automate. lessons learned from implementing continuous delivery
Don't hate, automate. lessons learned from implementing continuous deliveryDon't hate, automate. lessons learned from implementing continuous delivery
Don't hate, automate. lessons learned from implementing continuous delivery
 
Boston MeetUp 10.10
Boston MeetUp 10.10Boston MeetUp 10.10
Boston MeetUp 10.10
 
NYC MeetUp 10.9
NYC MeetUp 10.9NYC MeetUp 10.9
NYC MeetUp 10.9
 
Automated testing san francisco oct 2013
Automated testing san francisco oct 2013Automated testing san francisco oct 2013
Automated testing san francisco oct 2013
 

Recently uploaded

Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.YounusS2
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URLRuncy Oommen
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdfPedro Manuel
 
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfJamie (Taka) Wang
 
How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?IES VE
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaborationbruanjhuli
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarPrecisely
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024SkyPlanner
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UbiTrack UK
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
Building AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxUdaiappa Ramachandran
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDELiveplex
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsSafe Software
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Commit University
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPathCommunity
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsSeth Reyes
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding TeamAdam Moalla
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfinfogdgmi
 

Recently uploaded (20)

Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URL
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdf
 
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
 
How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
Building AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptx
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and Hazards
 
20230104 - machine vision
20230104 - machine vision20230104 - machine vision
20230104 - machine vision
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdf
 

Object-Oriented BDD w/ Cucumber by Matt van Horn

  • 2. Who Am I? Senior  So(ware  Engineer  at  New  Relic 20  years  of  web  applica9on  development 12  years  of  TDD 5  years  of  BDD github.com/maFvanhorn  or  @nycplayer Thursday, October 3, 13
  • 3. New Relic CI Thursday, October 3, 13
  • 4. New Relic CI Github,  TDDium,  Jenkins Feature  branches,  Pull  Requests Automa9c  builds,  Code  reviews Automated  deploys,  but  some  manual  control Thursday, October 3, 13
  • 5. New Relic CI We  deploy  3x  per  day Automated  tes9ng  is  part  of  the  process However... Thursday, October 3, 13
  • 6. New Relic CI We  have  a  large,  slow  test  suite We  have  a  large,  legacy  Rails  app We  have  a  lack  of  up-­‐to-­‐date  documenta9on We  o(en  have  communica9on  issues Thursday, October 3, 13
  • 7. New Relic CI We  want  to  go  from  3x/day  to  ‘at  will’ We  are  dedica9ng  9me  to  improving  our  tests Automated  acceptance  tests  are  key (Faster  unit  tests  are  also  important) Thursday, October 3, 13
  • 9. Behavior Driven development BDD  is  a  second-­‐genera9on,  outside–in,  pull-­‐based,  mul9ple-­‐ stakeholder,  mul9ple-­‐scale,  high-­‐automa9on,  agile  methodology.   It  describes  a  cycle  of  interac9ons  with  well-­‐defined  outputs,   resul9ng  in  the  delivery  of  working,  tested  so(ware  that  maFers. -­‐  Dan  North Thursday, October 3, 13
  • 10. Behavior Driven Development “BDD  describes  TDD  done  well” -­‐  MaF  Wynne Thursday, October 3, 13
  • 11. Behavior Driven Development “Can  you  give  me  some  examples  (of  using  it)?” vs. “What  are  the  requirements  (for  implemen9ng  it)?” Thursday, October 3, 13
  • 12. Outside In Start  with  a  conversa9on Determine  the  business  value Provide  examples  of  use Thursday, October 3, 13
  • 13. Outside In  User  Interface Browser Views Controllers Models Thursday, October 3, 13
  • 14. Outside In  User  Interface Browser Views Controllers Models Cucumber RSpec Thursday, October 3, 13
  • 15. Outside In Red,  Green,  REFACTOR Outer  loop:  Features,   stories,  scenarios Inner  loop:  Unit  tests,   classes,  methods Cucumber Thursday, October 3, 13
  • 16. Red,  Green,  REFACTOR Outer  loop:  Features,   stories,  scenarios Inner  loop:  Unit  tests,   classes,  methods Outside In Cucumber RSpec Thursday, October 3, 13
  • 17. Outside In Cucumber RSpecRed,  Green,  REFACTOR Outer  loop:  Features,   stories,  scenarios Inner  loop:  Unit  tests,   classes,  methods Thursday, October 3, 13
  • 18. Outside In Cucumber RSpecRed,  Green,  REFACTOR Outer  loop:  Features,   stories,  scenarios Inner  loop:  Unit  tests,   classes,  methods Thursday, October 3, 13
  • 19. BDD TOOLS Cucumber,  RSpec,  FitNesse Gherkin Spinach,  Turnip,  Steak,  Filet Capybara,  Wa9r,  WebRAT Selenium,  Webkit,  PhantomJS,  Rack::Test Thursday, October 3, 13
  • 20. Cucumber Complaints Don’t  need  English,  code  is  fine Doesn’t  save  developer  9me BriFle  tests,  needing  constant  maintenance Thursday, October 3, 13
  • 22. Cucumber Done right Minimizes  miscommunica9on Hides  implementa9on  details Provides  robust  regression  tests Communicates  inten9ons Thursday, October 3, 13
  • 23. Cucumber Done right Cucumber  allows  us  to  inform,  in  plain  English,  the   intended  behavior  of  applica9ons  we  build  to  future   developers,  rather  than  forcing  them  to  spelunk   through  code  to  figure  it  out. -­‐  Ma,  Polito Thursday, October 3, 13
  • 25. Object ORiented Cucumber Keep  data  and  behavior  together Hide  implementa9on  details Send  messages  to  accomplish  tasks Thursday, October 3, 13
  • 26. Page Object URLs UI Elements Page Sections Domain Action Methods Browser Driver Thursday, October 3, 13
  • 27. Page Object Provides  a  model  for  a  web  UI Hides  details  of  dealing  with  browser Keeps  UI  details  in  one  place Enables  expressive  test  code Thursday, October 3, 13
  • 28. Site Prism Open  source  Ruby  gem   Provides  simple  DSL  for  page  Objects Exposes  Capybara  nodes Thursday, October 3, 13
  • 29. Technique Plain  English,  not  code  (or  pseudo-­‐code) Domain  concepts,  not  implementa9on  details Focus  on  the  value,  not  the  incidentals Thursday, October 3, 13
  • 30. Stories & Scenarios Impera9ve Scenario: Typical Meetup Given I am on the estimate page When I fill in "Guest count" with "10" And I fill in "Slice count" with "2" And I press "Get Estimate" Then I should see "You will need to order 3 pizzas" Thursday, October 3, 13
  • 31. “English  -­‐  we  hateses  it” Scenario: Typical Meetup Given I am on “/estimates/new” And I fill in "input#guests" with "10" And I fill in "input#slices" with "2" And I press "input[type=’submit’]" Then I should see "You will need to order 3 pizzas" Stories & Scenarios Thursday, October 3, 13
  • 32. Stories & Scenarios Declara9ve Scenario: Typical Meetup (Guests eat 2 slices each) Given There are 10 guests expected When I ask how much to order Then I will know I need to buy 3 pizzas Thursday, October 3, 13
  • 33. Examples Feature: Estimating Pizza Requirements In order to avoid wasting either pizza or money As an organizer I want to know how many pizzas I need to order Background: Given there are 10 guests expected Scenario: Typical meetup (Guests eat 2 slices) Given the guests are hungry When I ask how much to order Then I will know I need to buy 3 pizzas Scenario: Late-night meetup (Guests eat 3 slices) Given the guests are starving When I ask how much to order Then I will know I need to buy 4 pizzas Scenario: After-lunch meetup (Guests eat 1 slice) Given the guests are full When I ask how much to order Then I will know I need to buy 2 pizzas Thursday, October 3, 13
  • 34. StepDefinitions Use  methods  that  relate  to  the  domain Avoid  nes9ng  steps Mostly  black  box Some  white  box  can  be  very  useful Thursday, October 3, 13
  • 35. Examples Given(/^there are (d+) guests expected$/) do |guest_count| Site.new_estimate_page.guests_expected = guest_count end Given(/^the guests are (full|hungry|starving)$/) do |hunger_level| Site.new_estimate_page.hunger_level = hunger_level end When 'I ask how much to order' do Site.new_estimate_page.request_estimate end Then(/^I will know I need to buy (d+ pizzas)$/) do |pie_count| expect(Site.new_estimate_page).to have_text("#{pie_count}") end Thursday, October 3, 13
  • 36. Examples Given(/^there are (d+) guests expected$/) do |guest_count| Site.new_estimate_page.guests_expected = guest_count end Given(/^the guests are (full|hungry|starving)$/) do |hunger_level| Site.new_estimate_page.hunger_level = hunger_level end When 'I ask how much to order' do Site.new_estimate_page.request_estimate end Then(/^I will know I need to buy (d+ pizzas)$/) do |pie_count| expect(Site.new_estimate_page).to have_text("#{pie_count}") end Thursday, October 3, 13
  • 37. Examples # Utility class to provide easy access to page objects. class Site def self.current_page @current_page end def self.method_missing(meth_name, *args) klass = meth_name.to_s.classify @current_page = klass.constantize.new end end Thursday, October 3, 13
  • 38. Examples class NewEstimatePage < SitePrism::Page URL = Rails.application.routes.url_helpers.root_path set_url URL set_url_matcher %r(#{URL}) element :guests_field, "input[name='estimate[guest_count]']" element :slices_field, "input[name='estimate[slice_count]']" element :submit_btn, "input[name='commit']" # ... instance methods elided ... end Thursday, October 3, 13
  • 39. Examples class NewEstimatePage < SitePrism::Page URL = Rails.application.routes.url_helpers.root_path set_url URL set_url_matcher %r(#{URL}) element :guests_field, "input[name='estimate[guest_count]']" element :slices_field, "input[name='estimate[slice_count]']" element :submit_btn, "input[name='commit']" # ... instance methods elided ... end Thursday, October 3, 13
  • 40. Examples class NewEstimatePage < SitePrism::Page URL = Rails.application.routes.url_helpers.root_path set_url URL set_url_matcher %r(#{URL}) element :guests_field, "input[name='estimate[guest_count]']" element :slices_field, "input[name='estimate[slice_count]']" element :submit_btn, "input[name='commit']" # ... instance methods elided ... end Thursday, October 3, 13
  • 41. Examplesclass NewEstimatePage < SitePrism::Page # ... DSL elided ... def guests_expected=(guest_count) load unless displayed? guests_field.set guest_count end def hunger_level=(hunger) load unless displayed? slices_per_person = case hunger when 'full' then 1 when 'hungry' then 2 when 'starving' then 3 end slices_field.set slices_per_person end def request_estimate load unless displayed? submit_btn.click end end Thursday, October 3, 13
  • 45. Product Manager: “We  should  es9mate  beer  as  well” “It  should  work  the  same  way  as  pizza” Thursday, October 3, 13
  • 46. Application Changes: Change  es9mate  model Change  form  view Change  es9mate  view Change  es9mate  view  helper Thursday, October 3, 13
  • 47. Cucumber Changes: Change  scenarios Add  steps  for  new  scenario  changes Add  elements  to  page  model Add  methods  to  page  model  to  use  elements Thursday, October 3, 13
  • 48. Examples Scenario: Typical meetup Given the guests are hungry And the guests love beer When I ask how much to order Then I will know I need to buy 3 pizza pies And I will know I need to buy 1 case and 1 six-pack of beer Scenario: Late-night meetup Given the guests are starving And the guests like beer When I ask how much to order Then I will know I need to buy 4 pizza pies And I will know I need to buy 1 case of beer Scenario: After-lunch meetup Given the guests are full And the guests are underage When I ask how much to order Then I will know I need to buy 2 pizza pies And I will know I don't need to buy beer Thursday, October 3, 13
  • 49. Examples Given(/^the guests (like|love) beer$/) do |thirst| Site.new_estimate_page.thirst_level = thirst end Given(/^the guests are underage$/) do Site.new_estimate_page.thirst_level = 'none' end Then(/^I will know I need to buy ((?:d+ cases?)?(?: and )?(?:d+ six-packs?)? of beer)$/) do |content| expect(Site.new_estimate_page).to have_text(content) end Then(/^I will know I don't need to buy beer$/) do expect(Site.new_estimate_page).to have_text("no beer") end Thursday, October 3, 13
  • 50. Examples class NewEstimatePage < SitePrism::Page # ... URL matchers elided ... element :guests_field, "input[name='estimate[guest_count]']" element :slices_field, "input[name='estimate[slice_count]']" element :beers_field, "input[name='estimate[beer_count]']" element :submit_btn, "input[name='commit']" # ... other methods elided ... def thirst_level=(thirst) load unless displayed? beer_count = case thirst when 'none' then 0 when 'like' then 2 when 'love' then 3 end beers_field.set beer_count end end Thursday, October 3, 13
  • 54. Examples Given(/^there are (d+) guests expected$/) do |guest_count| Site.new_estimate_page.guests_expected = guest_count end Given(/^the guests are (full|hungry|starving)$/) do |hunger_level| Site.new_estimate_page.hunger_level = hunger_level end When 'I ask how much to order' do Site.new_estimate_page.request_estimate end Then(/^I will know I need to buy (d+ pizza pies)$/) do |pie_count| expect(Site.new_estimate_page).to have_text("#{pie_count}") end Thursday, October 3, 13
  • 55. HELPER Modules Helpers  are  glue  between  inten9on  and   implementa9on   Swapping  out  helpers  can  adapt  your  suite  to   different  plajorms  or  devices Page  Objects  are  for  page  based  UIs,  but  the   principles  can  be  applied  to  other  domains Thursday, October 3, 13
  • 56. Examples module WebHelper def guests_expected count Site.new_estimate_page.guests_expected = count end def general_hunger_level hunger Site.new_estimate_page.hunger_level = hunger end def general_thirst_level thirst Site.new_estimate_page.thirst_level = thirst end def submit_request_for_estimate Site.new_estimate_page.request_estimate end def verify_pizzas_needed num_pies expect(Site.new_estimate_page).to have_text("#{num_pies} pizza pies") end def verify_beer_needed beer_text expect(Site.new_estimate_page).to have_text(beer_text) end end World(WebHelper) Thursday, October 3, 13
  • 57. ExamplesTransform /(d+)/ do |num| num.to_i end Given /^there are (d+) guests expected$/ do |guest_count| guests_expected guest_count end Given /^the guests are (full|hungry|starving)$/ do |hunger| general_hunger_level hunger end Given /^the guests (like|love) beer$/ do |thirst| general_thirst_level thirst end When 'I ask how much to order' do submit_request_for_estimate end Then(/^I will know I need to buy (d+) pizza pies$/) do |pie_count| verify_pizzas_needed pie_count end Then(/^I will know I need to buy ((?:d+ cases?)?(?: and )?(?:d+ six-packs?)? of beer) $/) do |beer_text| verify_beer_needed beer_text end Thursday, October 3, 13
  • 58. Product Manager: “It’s  too  easy  to  make  typos.” “Last  week  Ted  ordered  33  beers  per  person.” “The  carpet  is  s9ll  not  completely  clean.” Thursday, October 3, 13
  • 59. Application Changes: Change  form  view  to  use  different  widgets Thursday, October 3, 13
  • 60. Cucumber Changes: Update  page  object  to  use  new  elements Thursday, October 3, 13
  • 61. Examples element :slices_field, "input[name='estimate[slice_count]']" element :beers_field, "input[name='estimate[beer_count]']" def hunger_level=(hunger) load unless displayed? slices_per_person = case hunger when 'full' then 1 when 'hungry' then 2 when 'starving' then 3 end slices_field.set slices_per_person end def thirst_level=(thirst) load unless displayed? beer_count = case thirst when 'none' then 0 when 'like' then 2 when 'love' then 3 end beers_field.set beer_count end Thursday, October 3, 13
  • 62. Examples class NewEstimatePage < SitePrism::Page element :hunger_select, "select[name='estimate[slice_count]']" element :thirst_select, "select[name='estimate[beer_count]']" def hunger_level=(hunger) load unless displayed? hunger_select.select hunger end def thirst_level=(thirst) load unless displayed? thirst_select.select case thirst when 'like' then 'thirsty' when 'love' then 'extremely thirsty' else 'none' end end end Thursday, October 3, 13
  • 65. Product Manager: “We’re  adding  a  registra9on  feature.” “Entering  the  number  of  guests  is  redundant.” “We’ll  count  the  guests  in  the  database.” Thursday, October 3, 13
  • 66. Application Changes: Create  Guest  model,  with  db  migra9on Add  guest  list  view  with  add  guest  form Add  guests  controller Change  routes  to  add  guest  routes Change  es9mate  form  view Change  es9mate  controller Thursday, October 3, 13
  • 67. Cucumber Changes: Change  the  step  that  sets  up  the  number  of   guests. Thursday, October 3, 13
  • 68. Examples Given /^there are (d+) guests expected$/ do |guest_count| guests_expected guest_count end Thursday, October 3, 13
  • 69. Examples Given /^there are (d+) guests expected$/ do |guest_count| guest_count.times{ Fabricate(:guest) } end Thursday, October 3, 13
  • 70. Alternative Change  the  implementa9on  of  the  method   the  step  calls. Thursday, October 3, 13
  • 72. Alternative def guests_expected guest_count guest_count.times{ Fabricate(:guest) } end Thursday, October 3, 13
  • 73. Alternative module DatabaseHelper def guests_expected guest_count guest_count.times{ Fabricate(:guest) } end end Thursday, October 3, 13
  • 74. Alternative # support/helpers/database_helper.rb module DatabaseHelper def guests_expected guest_count guest_count.times{ Fabricate(:guest) } end end # support/helpers/helper_setup.rb require_relative 'web_helper' require_relative 'database_helper' World(WebHelper) World(DatabaseHelper) Thursday, October 3, 13
  • 79. Examplesmodule PersonalAssistantHelper def general_hunger_level hunger PersonalAssistant.tell "Guests will be #{hunger}" end def general_thirst_level thirst PersonalAssistant.tell "Guests will #{thirst} beer" unless thirst == 'none' end def submit_request_for_estimate PersonalAssistant.ask "How much do I need?" end def verify_pizzas_needed num_pies expect(PersonalAssistant.guess_pizza).to eq(num_pies) end def verify_beer_needed beer_text expect(PersonalAssistant.guess_beer).to eq(beer_text) end end Thursday, October 3, 13
  • 80. SUMMARY Keep  implementa9on  details  in  one  place Use  objects  to  model  the  system Use  abstrac9on  levels  to  scope  changes Express  your  intent  throughout  the  code Thursday, October 3, 13