SlideShare une entreprise Scribd logo
1  sur  149
BDD FROM THE
                   Luismi Cavallé
TRENCHES     Jorge Gómez Sancha
                            BeBanjo
As a [Role]
I want [Feature]
So that [Benefit]

Scenario = Acceptance Criteria

  Given [Context]
  And [Some more Context]

  When [Event]
  And [Some other Event]

  Then [Outcome]
  And [Another Outcome]
Given [Context]   Planteamiento



When [Event]      Nudo



Then [Outcome]    Desenlace
User Stories
                  =
Great way to communicate functionality
Searching for “THE WAY” to develop software
We have made good progress...
...but we are always searching
HOW
HOW
  H
  Y
Friday
(afternoon)
What’s the most
important thing the
 system doesn’t do?


              http://dannorth.net/introducing-bdd
Feature
       Feature
                                  Feature
                                                       Feature




                  Feature

                                            Feature
                                  Feature




Feature          Feature
                            Feature
            Feature                          Feature




                 Feature
  Feature
Feature
  Feature
  Feature
  Feature
   Feature
    Feature
     Feature
Story: User sees timeline for a title

  As a user,
  I want to see a timeline of all the events associated to a title,
  So that I have access to its full history

  Scenario: An entry in the title timeline gets created when scheduled

    Given Telefonica operates VOD services Imagenio
    And a user Borat from the company Telefonica
    And Pedro scheduled the title Spaceballs on 15-03-2008 in Imagenio

    When Borat logs in
    And Borat goes to the title's timeline page for title Spaceballs

    Then he should see an entry 'Scheduled by Borat' on March 15, 2008
It’s game time
Would you mind giving me some privacy?
Would you mind giving me some privacy?
                      Porras



LuisMi
Estimates


Features   L
           uismi   R J
                    ai     orge   S   ergio


  A        3       2       4      3
  B        1       .5      2      1
  C        1       .5    15
                          .       1
  D        15
           .       1     15
                          .       2
Estimates             We use these


Features   L
           uismi   R J
                    ai     orge   S   ergio   Average


  A        3       2       4      3           3
  B        1       .5      2      1           11
                                               .
  C        1       .5    15
                          .       1               1
  D        15
           .       1     15
                          .       2           15
                                               .
Burndown Junkies
Functionality
        Left




                 F          M   T   W   Th

                     Time
Black Monday
Progress               Ideal Preso


✓ Estimating, Game, Burndown   20     100

  Pair Programming             20
                                       75

  Acceptance vs Unit           20
                                       50
  Upfront Design               10
                                       25
  Love                         10
                                        0
  Productivity                 20           40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End!


                          Total 100
                                                              Left: 80
Monday
“Pair all the fucking time”
                  -- Obie Fernandez
“Aparéate todo el puto día”
                     -- BeBanjo
“Aparéate todo el puto día”
                     -- BeBanjo
# /bebanjo_app/features/login.feature




Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt'
  When Robert logs in entering the password 'r0b3rt'
  Then he should be redirected to the home page
$ cd bebanjo_app
$ cd bebanjo_app
$ script/cucumber features/login.feature
$ cd bebanjo_app
$ script/cucumber features/login.feature


Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt' [PENDING]
  When Robert logs in entering the password 'r0b3rt'   [PENDING]
  Then he should be redirected to the home page        [PENDING]
# /bebanjo_app/features/steps/user_steps.rb
# /bebanjo_app/features/steps/user_steps.rb




Given /^an existing user (.*) with password '(.*)'$/ do |username, password|
# /bebanjo_app/features/steps/user_steps.rb




Given /^an existing user (.*) with password '(.*)'$/ do |username, password|
  User.create(:username => username, :password => password)
# /bebanjo_app/features/steps/user_steps.rb




Given /^an existing user (.*) with password '(.*)'$/ do |username, password|
  User.create(:username => username, :password => password)
end
$ script/cucumber features/login.feature
$ script/cucumber features/login.feature


Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt' [FAILED]
    uninitialized constant User (NameError)
  When Robert logs in entering the password 'r0b3rt'   [PENDING]
  Then he should be redirected to the home page        [PENDING]
$ script/cucumber features/login.feature


Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt' [FAILED]
    uninitialized constant User (NameError)
  When Robert logs in entering the password 'r0b3rt'   [PENDING]
  Then he should be redirected to the home page        [PENDING]
$ script/generate model User username:string password:string
$ script/generate model User username:string password:string

$ rake db:migrate && rake db:test:prepare
$ script/cucumber features/login.feature
$ script/cucumber features/login.feature

Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt'
  When Robert logs in entering the password 'r0b3rt'   [PENDING]
  Then he should be redirected to the home page        [PENDING]
# /bebanjo_app/features/steps/user_steps.rb




When /^(.*) logs in entering the password '(.*)'$/ do |username, password|
# /bebanjo_app/features/steps/user_steps.rb




When /^(.*) logs in entering the password '(.*)'$/ do |username, password|
  visits quot;/session/newquot;
# /bebanjo_app/features/steps/user_steps.rb




When /^(.*) logs in entering the password '(.*)'$/ do |username, password|
  visits quot;/session/newquot;
  fills_in quot;Usernamequot;, :with => username
# /bebanjo_app/features/steps/user_steps.rb




When /^(.*) logs in entering the password '(.*)'$/ do |username, password|
  visits quot;/session/newquot;
  fills_in quot;Usernamequot;, :with => username
  fills_in quot;Passwordquot;, :with => password
# /bebanjo_app/features/steps/user_steps.rb




When /^(.*) logs in entering the password '(.*)'$/ do |username, password|
  visits quot;/session/newquot;
  fills_in quot;Usernamequot;, :with => username
  fills_in quot;Passwordquot;, :with => password
  clicks_button quot;Sign inquot;
# /bebanjo_app/features/steps/user_steps.rb




When /^(.*) logs in entering the password '(.*)'$/ do |username, password|
  visits quot;/session/newquot;
  fills_in quot;Usernamequot;, :with => username
  fills_in quot;Passwordquot;, :with => password
  clicks_button quot;Sign inquot;
end
$ script/cucumber features/login.feature
$ script/cucumber features/login.feature

Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt'
  When Robert logs in entering the password 'r0b3rt'   [FAILED]
    No route matches quot;/session/newquot; with {:method=>:get} (RoutingError)
  Then he should be redirected to the home page        [PENDING]
$ script/cucumber features/login.feature

Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt'
  When Robert logs in entering the password 'r0b3rt'   [FAILED]
    No route matches quot;/session/newquot; with {:method=>:get} (RoutingError)
  Then he should be redirected to the home page        [PENDING]
# /bebanjo_app/config/routes.rb




       ActionController::Routing::Routes.draw do |map|
         map.resource :session
# /bebanjo_app/app/controllers/sessions_controller.rb
# /bebanjo_app/app/controllers/sessions_controller.rb



      class SessionsController < ApplicationController
# /bebanjo_app/app/controllers/sessions_controller.rb



      class SessionsController < ApplicationController
        def new
# /bebanjo_app/app/controllers/sessions_controller.rb



      class SessionsController < ApplicationController
        def new
        end
# /bebanjo_app/app/controllers/sessions_controller.rb



      class SessionsController < ApplicationController
        def new
        end

        def create
# /bebanjo_app/app/controllers/sessions_controller.rb



      class SessionsController < ApplicationController
        def new
        end

        def create
        end
# /bebanjo_app/app/controllers/sessions_controller.rb



      class SessionsController < ApplicationController
        def new
        end

        def create
        end
      end
# /bebanjo_app/app/views/sessions/new.html.erb


   <% form_for :session, :url => session_path do |f| -%>
   <p>
     <%= f.label :username %>:
     <%= f.text_field :username %>
   </p>
   <p>
     <%= f.label :password %>:
     <%= f.password_field :password %>
   </p>
   <p>
     <%= f.submit quot;Sign inquot; %>
   </p> <% end -%>
$ script/cucumber features/login.feature
$ script/cucumber features/login.feature

Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt'
  When Robert logs in entering the password 'r0b3rt'
  Then he should be redirected to the home page        [PENDING]
# /bebanjo_app/features/steps/user_steps.rb




 Then /^(?:he|she) should be redirected to the home page$/ do
   response.request.path.should == quot;/quot;
 end
$ script/cucumber features/login.feature
$ script/cucumber features/login.feature


Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt'
  When Robert logs in entering the password 'r0b3rt'
  Then he should be redirected to the home page        [FAILED]
    expected redirect to quot;/quot;, got no redirect (ExpectationNotMetError)
$ script/cucumber features/login.feature


Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt'
  When Robert logs in entering the password 'r0b3rt'
  Then he should be redirected to the home page        [FAILED]
    expected redirect to quot;/quot;, got no redirect (ExpectationNotMetError)
# /bebanjo_app/app/controllers/sessions_controller.rb


      class SessionsController < ApplicationController
        def new
        end

        def create
          redirect_to root_path
        end
      end
$ script/cucumber features/login.feature
$ script/cucumber features/login.feature


Scenario: User logs in successfully
  Given an existing user Robert with password 'r0b3rt'
  When Robert logs in entering the password 'r0b3rt'
  Then he should be redirected to the home page

3 steps passed
# /bebanjo_app/features/login.feature




   Scenario: User logs in with incorrect credentials
       Given an existing user Robert with password 'r0b3rt'
       When Robert logs in entering the password 'robert'
       Then he should not be redirected to the home page
$ git commit -a -m “Scenario: User logs in successfully”
$ git commit -a -m “Scenario: User logs in successfully”

$ git push origin master
Story driven

Swapping Criteria
Increased Focus

Knowledge share

  Pride Effect
Progress               Ideal Preso


✓ Estimating, Game, Burndown   20     100

✓ Pair Programming             20
                                       75

  Acceptance vs Unit           20
                                       50
  Upfront Design               10
                                       25
  Love                         10
                                        0
  Productivity                 20           40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End!


                          Total 100
                                                              Left: 60
Tuesday
Acceptance   Unit
Acceptance   Unit
Acceptance   Unit
Acceptance                      Unit


                         Development / Design
Great verification tool
                         tool
Acceptance
# user_steps.rb

Given /^an existing user (.*)$/ do |username|
  create_user(:username => username)
end
# user_steps.rb

Given /^an existing user (.*)$/ do |username|
  create_user(:username => username)
end




# example_data.rb (fixture_replacement)

attributes_for :user do |u|
  u.username              =   String.random
  u.password              =   quot;secretquot;
  u.password_confirmation =   quot;secretquot;
  u.company               =   default_company
end
# user_steps.rb

When /^(.*) logs in$/ do |username|
  visits quot;/session/newquot;
  fills_in quot;Usernamequot;, :with => username
  fills_in quot;Passwordquot;, :with => quot;secretquot;
  clicks_button quot;Sign inquot;
end
# user_steps.rb

Then /^the email of (.*) should be (.*)/ do |username, email|
  user = User.find_by_username(username)
  user.email.should == email # assert_equal(email, user.email)
end
# user_steps.rb

 Then /^the email of (.*) should be (.*)/ do |username, email|
   user = User.find_by_username(username)
   user.email.should == email # assert_equal(email, user.email)
 end




Then /^the user should see the title (.*)/ do |title|
  response.should have_tag(quot;.titlequot;, title) # assert_select(quot;.titlequot;, title)
end
Acceptance testing is great...
Acceptance testing is great...
  • as a verification tool
Acceptance testing is great...
  • as a verification tool
  • as a bridge between user needs and automated
     tests
Acceptance testing is great...
  • as a verification tool
  • as a bridge between user needs and automated
     tests
        ...but as a development tool....
Acceptance testing is great...
  • as a verification tool
  • as a bridge between user needs and automated
     tests
        ...but as a development tool....
             • it is not easy to debug
Acceptance testing is great...
  • as a verification tool
  • as a bridge between user needs and automated
     tests
        ...but as a development tool....
             • it is not easy to debug
             • it is slow to run
Acceptance testing is great...
  • as a verification tool
  • as a bridge between user needs and automated
     tests
        ...but as a development tool....
             • it is not easy to debug
             • it is slow to run
             • it doesn’t encourage good design
Acceptance testing is great...
  • as a verification tool
  • as a bridge between user needs and automated
     tests
        ...but as a development tool....
             •   it is not easy to debug
             •   it is slow to run
             •   it doesn’t encourage good design
             •   it is not comprehensive
Acceptance testing is great...
  • as a verification tool
  • as a bridge between user needs and automated
     tests
        ...but as a development tool....
             •   it is not easy to debug
             •   it is slow to run
             •   it doesn’t encourage good design
             •   it is not comprehensive

                   ...so we need something more
Unit
RSpec offers lots of possibilities:
RSpec offers lots of possibilities:


 Model specs
Controller specs
  View specs
 Helper specs
 Routes specs
RSpec offers lots of possibilities:


 Model specs
Controller specs               Interaction-based
  View specs                      State-based
 Helper specs                   Structure-based
 Routes specs
But we’re only interested in:

 Maximize Productivity
  Maximize Quality
So, how do we spec...

                        Our Views?
So, how do we spec...

                        Our Views?

         We mostly don’t
So, how do we spec...

                        Our Views?

         We mostly don’t

         Redundant with “then” steps in stories
So, how do we spec...

             Our Controllers?
So, how do we spec...

             Our Controllers?

                  67% Coverage
So, how do we spec...

             Our Controllers?

                  67% Coverage

                  Interaction-based unit test
So, how do we spec...

             Our Controllers?

                  67% Coverage

                  Interaction-based unit test

                  Still discussing if it is worth
# tasks_controller_spec.rb

describe quot;POST 'create'quot; do

   before(:each) do
    @task_attibutes = stub(Hash)
    @task = stub(Task)
    @tasks.stub!(:create).and_return(@task)
  end

  def do_post
    post :create, :scheduled_title_id => 1, :task => @task_attributes
  end

 it quot;should get the scheduled title from the current companyquot; do
   @scheduled_titles.should_receive(:find).with(quot;1quot;).and_return(@scheduled_title)
   do_post
 end

 it quot;should create the taskquot; do
   @tasks.should_receive(:create).with(@task_attributes)
   do_post
 end

 it quot;should redirect to workflowquot; do
   do_post
   assigns[:task].should == @task
 end

end
So, how do we spec...

                Our Models?
So, how do we spec...

                Our Models?
                   87% Coverage
So, how do we spec...

                Our Models?
                   87% Coverage

                   State-based functional test
So, how do we spec...

                Our Models?
                   87% Coverage

                   State-based functional test

                   Only the interesting behavior
describe ScheduledTitle do

 describe quot;late?quot; do

   it quot;should be late if begins_at is in the pastquot; do
     scheduled_title = new_scheduled_title(:begins_at => Date.today - 3.days)
     scheduled_title.should be_late
   end

   it quot;should not be late if begins_at is in the futurequot; do
     scheduled_title = new_scheduled_title(:begins_at => Date.today + 3.days)
     scheduled_title.should_not be_late
   end

   it quot;should not be late if begins_at is todayquot; do
     scheduled_title = new_scheduled_title(:begins_at => Date.today)
     scheduled_title.should_not be_late
   end

  end
So, how do we spec...

               Other objects?
So, how do we spec...

               Other objects?
              Helpers -- 32.1% Coverage
So, how do we spec...

               Other objects?
              Helpers -- 32.1% Coverage

              Routes -- never
So, how do we spec...

               Other objects?
              Helpers -- 32.1% Coverage

              Routes -- never

              Libs -- 86.7%
How do we not spec?
describe User do

          it { Factory(:user).should have_many(:projects) }
          it { Factory(:user).should belong_to(:company) }

          table_has_columns(User, :string,   quot;loginquot;)

        end




class User
  has_many :projects
  belongs_to :company
describe User do

          it { Factory(:user).should have_many(:projects) }
          it { Factory(:user).should belong_to(:company) }

          table_has_columns(User, :string,   quot;loginquot;)

        end




class User                      create_table quot;usersquot;, :force => true do |t|
  has_many :projects              t.column :login, :string
                                end
  belongs_to :company
describe User do

          it { Factory(:user).should have_many(:projects) }
          it { Factory(:user).should belong_to(:company) }

          table_has_columns(User, :string,   quot;loginquot;)

        end




      Structure is not interesting behavior!


class User                      create_table quot;usersquot;, :force => true do |t|
  has_many :projects              t.column :login, :string
                                end
  belongs_to :company
Progress               Ideal Preso


✓ Estimating, Game, Burndown   20     100

✓ Pair Programming             20
                                       75

✓ Acceptance vs Unit           20
                                       50
  Upfront Design               10
                                       25
  Love                         10
                                        0
  Productivity                 20           40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End!


                          Total 100
                                                              Left: 40
Wednesday
Playboy TV
Progress               Ideal Preso


✓ Estimating, Game, Burndown   20     100

✓ Pair Programming             20
                                       75

✓ Acceptance vs Unit           20
                                       50
✓ Upfront Design               10
                                       25
  Love                         10
                                        0
  Productivity                 20           40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End!


                          Total 100
                                                              Left: 30
Thursday
DRY




Less code         Skinny controller, fat model
Technical debt

                 DRY




   Less code           Skinny controller, fat model
Technical debt            Broken windows

                 DRY




   Less code           Skinny controller, fat model
Technical debt            Broken windows

                 DRY




   Less code           Skinny controller, fat model

                           Beautiful code
Technical debt              Broken windows

                     DRY




     Less code             Skinny controller, fat model

Habitable software             Beautiful code
Technical debt              Broken windows

                     DRY


          Refactoring towards
           a deeper insight
     Less code             Skinny controller, fat model

Habitable software             Beautiful code
Progress               Ideal Preso


✓ Estimating, Game, Burndown   20     100

✓ Pair Programming             20
                                       75

✓ Acceptance vs Unit           20
                                       50
✓ Upfront Design               10
                                       25
✓ Love                         10
                                        0
  Productivity                 20           40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End!


                          Total 100
                                                              Left: 20
and again, Friday
You call that productivity?
The End

Contenu connexe

Similaire à Bdd From The Trenches

Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Aslak Hellesøy
 
Baremetal deployment
Baremetal deploymentBaremetal deployment
Baremetal deployment
baremetal
 
Baremetal deployment scale
Baremetal deployment scaleBaremetal deployment scale
Baremetal deployment scale
baremetal
 

Similaire à Bdd From The Trenches (20)

Userstories a practical intro
Userstories a practical introUserstories a practical intro
Userstories a practical intro
 
Shipping your product overseas!
Shipping your product overseas!Shipping your product overseas!
Shipping your product overseas!
 
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.io
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.ioContinuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.io
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.io
 
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
 
Have Better Toys
Have Better ToysHave Better Toys
Have Better Toys
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manor
 
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac..."Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
 
Aprendendo solid com exemplos
Aprendendo solid com exemplosAprendendo solid com exemplos
Aprendendo solid com exemplos
 
Baremetal deployment
Baremetal deploymentBaremetal deployment
Baremetal deployment
 
CUCUMBER - Making BDD Fun
CUCUMBER - Making BDD FunCUCUMBER - Making BDD Fun
CUCUMBER - Making BDD Fun
 
RSpec User Stories
RSpec User StoriesRSpec User Stories
RSpec User Stories
 
Cooking Up Drama
Cooking Up DramaCooking Up Drama
Cooking Up Drama
 
Cooking Up Drama - ChefConf 2015
Cooking Up Drama - ChefConf 2015 Cooking Up Drama - ChefConf 2015
Cooking Up Drama - ChefConf 2015
 
Bowtie: Interactive Dashboards
Bowtie: Interactive DashboardsBowtie: Interactive Dashboards
Bowtie: Interactive Dashboards
 
Baremetal deployment scale
Baremetal deployment scaleBaremetal deployment scale
Baremetal deployment scale
 
Arduino programming of ML-style in ATS
Arduino programming of ML-style in ATSArduino programming of ML-style in ATS
Arduino programming of ML-style in ATS
 
AngularJS in practice
AngularJS in practiceAngularJS in practice
AngularJS in practice
 
Getting Started with Test Automation: Introduction to Cucumber with Lapis Lazuli
Getting Started with Test Automation: Introduction to Cucumber with Lapis LazuliGetting Started with Test Automation: Introduction to Cucumber with Lapis Lazuli
Getting Started with Test Automation: Introduction to Cucumber with Lapis Lazuli
 
More Secrets of JavaScript Libraries
More Secrets of JavaScript LibrariesMore Secrets of JavaScript Libraries
More Secrets of JavaScript Libraries
 
Introduction to Ruby on Rails
Introduction to Ruby on RailsIntroduction to Ruby on Rails
Introduction to Ruby on Rails
 

Dernier

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Dernier (20)

Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 

Bdd From The Trenches

  • 1. BDD FROM THE Luismi Cavallé TRENCHES Jorge Gómez Sancha BeBanjo
  • 2. As a [Role] I want [Feature] So that [Benefit] Scenario = Acceptance Criteria Given [Context] And [Some more Context] When [Event] And [Some other Event] Then [Outcome] And [Another Outcome]
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8. Given [Context] Planteamiento When [Event] Nudo Then [Outcome] Desenlace
  • 9.
  • 10.
  • 11. User Stories = Great way to communicate functionality
  • 12. Searching for “THE WAY” to develop software
  • 13. We have made good progress...
  • 14. ...but we are always searching
  • 15.
  • 16. HOW
  • 17. HOW H Y
  • 19. What’s the most important thing the system doesn’t do? http://dannorth.net/introducing-bdd
  • 20. Feature Feature Feature Feature Feature Feature Feature Feature Feature Feature Feature Feature Feature Feature
  • 21. Feature Feature Feature Feature Feature Feature Feature
  • 22. Story: User sees timeline for a title As a user, I want to see a timeline of all the events associated to a title, So that I have access to its full history Scenario: An entry in the title timeline gets created when scheduled Given Telefonica operates VOD services Imagenio And a user Borat from the company Telefonica And Pedro scheduled the title Spaceballs on 15-03-2008 in Imagenio When Borat logs in And Borat goes to the title's timeline page for title Spaceballs Then he should see an entry 'Scheduled by Borat' on March 15, 2008
  • 24. Would you mind giving me some privacy?
  • 25. Would you mind giving me some privacy? Porras LuisMi
  • 26. Estimates Features L uismi R J ai orge S ergio A 3 2 4 3 B 1 .5 2 1 C 1 .5 15 . 1 D 15 . 1 15 . 2
  • 27. Estimates We use these Features L uismi R J ai orge S ergio Average A 3 2 4 3 3 B 1 .5 2 1 11 . C 1 .5 15 . 1 1 D 15 . 1 15 . 2 15 .
  • 28. Burndown Junkies Functionality Left F M T W Th Time
  • 30. Progress Ideal Preso ✓ Estimating, Game, Burndown 20 100 Pair Programming 20 75 Acceptance vs Unit 20 50 Upfront Design 10 25 Love 10 0 Productivity 20 40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End! Total 100 Left: 80
  • 32. “Pair all the fucking time” -- Obie Fernandez
  • 33. “Aparéate todo el puto día” -- BeBanjo
  • 34.
  • 35. “Aparéate todo el puto día” -- BeBanjo
  • 36. # /bebanjo_app/features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'r0b3rt' Then he should be redirected to the home page
  • 38. $ cd bebanjo_app $ script/cucumber features/login.feature
  • 39. $ cd bebanjo_app $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' [PENDING] When Robert logs in entering the password 'r0b3rt' [PENDING] Then he should be redirected to the home page [PENDING]
  • 41. # /bebanjo_app/features/steps/user_steps.rb Given /^an existing user (.*) with password '(.*)'$/ do |username, password|
  • 42. # /bebanjo_app/features/steps/user_steps.rb Given /^an existing user (.*) with password '(.*)'$/ do |username, password| User.create(:username => username, :password => password)
  • 43. # /bebanjo_app/features/steps/user_steps.rb Given /^an existing user (.*) with password '(.*)'$/ do |username, password| User.create(:username => username, :password => password) end
  • 45. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' [FAILED] uninitialized constant User (NameError) When Robert logs in entering the password 'r0b3rt' [PENDING] Then he should be redirected to the home page [PENDING]
  • 46. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' [FAILED] uninitialized constant User (NameError) When Robert logs in entering the password 'r0b3rt' [PENDING] Then he should be redirected to the home page [PENDING]
  • 47. $ script/generate model User username:string password:string
  • 48. $ script/generate model User username:string password:string $ rake db:migrate && rake db:test:prepare
  • 50. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'r0b3rt' [PENDING] Then he should be redirected to the home page [PENDING]
  • 51. # /bebanjo_app/features/steps/user_steps.rb When /^(.*) logs in entering the password '(.*)'$/ do |username, password|
  • 52. # /bebanjo_app/features/steps/user_steps.rb When /^(.*) logs in entering the password '(.*)'$/ do |username, password| visits quot;/session/newquot;
  • 53. # /bebanjo_app/features/steps/user_steps.rb When /^(.*) logs in entering the password '(.*)'$/ do |username, password| visits quot;/session/newquot; fills_in quot;Usernamequot;, :with => username
  • 54. # /bebanjo_app/features/steps/user_steps.rb When /^(.*) logs in entering the password '(.*)'$/ do |username, password| visits quot;/session/newquot; fills_in quot;Usernamequot;, :with => username fills_in quot;Passwordquot;, :with => password
  • 55. # /bebanjo_app/features/steps/user_steps.rb When /^(.*) logs in entering the password '(.*)'$/ do |username, password| visits quot;/session/newquot; fills_in quot;Usernamequot;, :with => username fills_in quot;Passwordquot;, :with => password clicks_button quot;Sign inquot;
  • 56. # /bebanjo_app/features/steps/user_steps.rb When /^(.*) logs in entering the password '(.*)'$/ do |username, password| visits quot;/session/newquot; fills_in quot;Usernamequot;, :with => username fills_in quot;Passwordquot;, :with => password clicks_button quot;Sign inquot; end
  • 58. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'r0b3rt' [FAILED] No route matches quot;/session/newquot; with {:method=>:get} (RoutingError) Then he should be redirected to the home page [PENDING]
  • 59. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'r0b3rt' [FAILED] No route matches quot;/session/newquot; with {:method=>:get} (RoutingError) Then he should be redirected to the home page [PENDING]
  • 60. # /bebanjo_app/config/routes.rb ActionController::Routing::Routes.draw do |map| map.resource :session
  • 62. # /bebanjo_app/app/controllers/sessions_controller.rb class SessionsController < ApplicationController
  • 63. # /bebanjo_app/app/controllers/sessions_controller.rb class SessionsController < ApplicationController def new
  • 64. # /bebanjo_app/app/controllers/sessions_controller.rb class SessionsController < ApplicationController def new end
  • 65. # /bebanjo_app/app/controllers/sessions_controller.rb class SessionsController < ApplicationController def new end def create
  • 66. # /bebanjo_app/app/controllers/sessions_controller.rb class SessionsController < ApplicationController def new end def create end
  • 67. # /bebanjo_app/app/controllers/sessions_controller.rb class SessionsController < ApplicationController def new end def create end end
  • 68. # /bebanjo_app/app/views/sessions/new.html.erb <% form_for :session, :url => session_path do |f| -%> <p> <%= f.label :username %>: <%= f.text_field :username %> </p> <p> <%= f.label :password %>: <%= f.password_field :password %> </p> <p> <%= f.submit quot;Sign inquot; %> </p> <% end -%>
  • 70. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'r0b3rt' Then he should be redirected to the home page [PENDING]
  • 71. # /bebanjo_app/features/steps/user_steps.rb Then /^(?:he|she) should be redirected to the home page$/ do response.request.path.should == quot;/quot; end
  • 73. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'r0b3rt' Then he should be redirected to the home page [FAILED] expected redirect to quot;/quot;, got no redirect (ExpectationNotMetError)
  • 74. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'r0b3rt' Then he should be redirected to the home page [FAILED] expected redirect to quot;/quot;, got no redirect (ExpectationNotMetError)
  • 75. # /bebanjo_app/app/controllers/sessions_controller.rb class SessionsController < ApplicationController def new end def create redirect_to root_path end end
  • 77. $ script/cucumber features/login.feature Scenario: User logs in successfully Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'r0b3rt' Then he should be redirected to the home page 3 steps passed
  • 78. # /bebanjo_app/features/login.feature Scenario: User logs in with incorrect credentials Given an existing user Robert with password 'r0b3rt' When Robert logs in entering the password 'robert' Then he should not be redirected to the home page
  • 79. $ git commit -a -m “Scenario: User logs in successfully”
  • 80. $ git commit -a -m “Scenario: User logs in successfully” $ git push origin master
  • 81.
  • 84. Progress Ideal Preso ✓ Estimating, Game, Burndown 20 100 ✓ Pair Programming 20 75 Acceptance vs Unit 20 50 Upfront Design 10 25 Love 10 0 Productivity 20 40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End! Total 100 Left: 60
  • 86. Acceptance Unit
  • 87. Acceptance Unit
  • 88. Acceptance Unit
  • 89. Acceptance Unit Development / Design Great verification tool tool
  • 91. # user_steps.rb Given /^an existing user (.*)$/ do |username| create_user(:username => username) end
  • 92. # user_steps.rb Given /^an existing user (.*)$/ do |username| create_user(:username => username) end # example_data.rb (fixture_replacement) attributes_for :user do |u| u.username = String.random u.password = quot;secretquot; u.password_confirmation = quot;secretquot; u.company = default_company end
  • 93. # user_steps.rb When /^(.*) logs in$/ do |username| visits quot;/session/newquot; fills_in quot;Usernamequot;, :with => username fills_in quot;Passwordquot;, :with => quot;secretquot; clicks_button quot;Sign inquot; end
  • 94. # user_steps.rb Then /^the email of (.*) should be (.*)/ do |username, email| user = User.find_by_username(username) user.email.should == email # assert_equal(email, user.email) end
  • 95. # user_steps.rb Then /^the email of (.*) should be (.*)/ do |username, email| user = User.find_by_username(username) user.email.should == email # assert_equal(email, user.email) end Then /^the user should see the title (.*)/ do |title| response.should have_tag(quot;.titlequot;, title) # assert_select(quot;.titlequot;, title) end
  • 97. Acceptance testing is great... • as a verification tool
  • 98. Acceptance testing is great... • as a verification tool • as a bridge between user needs and automated tests
  • 99. Acceptance testing is great... • as a verification tool • as a bridge between user needs and automated tests ...but as a development tool....
  • 100. Acceptance testing is great... • as a verification tool • as a bridge between user needs and automated tests ...but as a development tool.... • it is not easy to debug
  • 101. Acceptance testing is great... • as a verification tool • as a bridge between user needs and automated tests ...but as a development tool.... • it is not easy to debug • it is slow to run
  • 102. Acceptance testing is great... • as a verification tool • as a bridge between user needs and automated tests ...but as a development tool.... • it is not easy to debug • it is slow to run • it doesn’t encourage good design
  • 103. Acceptance testing is great... • as a verification tool • as a bridge between user needs and automated tests ...but as a development tool.... • it is not easy to debug • it is slow to run • it doesn’t encourage good design • it is not comprehensive
  • 104. Acceptance testing is great... • as a verification tool • as a bridge between user needs and automated tests ...but as a development tool.... • it is not easy to debug • it is slow to run • it doesn’t encourage good design • it is not comprehensive ...so we need something more
  • 105. Unit
  • 106. RSpec offers lots of possibilities:
  • 107. RSpec offers lots of possibilities: Model specs Controller specs View specs Helper specs Routes specs
  • 108. RSpec offers lots of possibilities: Model specs Controller specs Interaction-based View specs State-based Helper specs Structure-based Routes specs
  • 109. But we’re only interested in: Maximize Productivity Maximize Quality
  • 110. So, how do we spec... Our Views?
  • 111. So, how do we spec... Our Views? We mostly don’t
  • 112. So, how do we spec... Our Views? We mostly don’t Redundant with “then” steps in stories
  • 113. So, how do we spec... Our Controllers?
  • 114. So, how do we spec... Our Controllers? 67% Coverage
  • 115. So, how do we spec... Our Controllers? 67% Coverage Interaction-based unit test
  • 116. So, how do we spec... Our Controllers? 67% Coverage Interaction-based unit test Still discussing if it is worth
  • 117. # tasks_controller_spec.rb describe quot;POST 'create'quot; do before(:each) do @task_attibutes = stub(Hash) @task = stub(Task) @tasks.stub!(:create).and_return(@task) end def do_post post :create, :scheduled_title_id => 1, :task => @task_attributes end it quot;should get the scheduled title from the current companyquot; do @scheduled_titles.should_receive(:find).with(quot;1quot;).and_return(@scheduled_title) do_post end it quot;should create the taskquot; do @tasks.should_receive(:create).with(@task_attributes) do_post end it quot;should redirect to workflowquot; do do_post assigns[:task].should == @task end end
  • 118. So, how do we spec... Our Models?
  • 119. So, how do we spec... Our Models? 87% Coverage
  • 120. So, how do we spec... Our Models? 87% Coverage State-based functional test
  • 121. So, how do we spec... Our Models? 87% Coverage State-based functional test Only the interesting behavior
  • 122. describe ScheduledTitle do describe quot;late?quot; do it quot;should be late if begins_at is in the pastquot; do scheduled_title = new_scheduled_title(:begins_at => Date.today - 3.days) scheduled_title.should be_late end it quot;should not be late if begins_at is in the futurequot; do scheduled_title = new_scheduled_title(:begins_at => Date.today + 3.days) scheduled_title.should_not be_late end it quot;should not be late if begins_at is todayquot; do scheduled_title = new_scheduled_title(:begins_at => Date.today) scheduled_title.should_not be_late end end
  • 123. So, how do we spec... Other objects?
  • 124. So, how do we spec... Other objects? Helpers -- 32.1% Coverage
  • 125. So, how do we spec... Other objects? Helpers -- 32.1% Coverage Routes -- never
  • 126. So, how do we spec... Other objects? Helpers -- 32.1% Coverage Routes -- never Libs -- 86.7%
  • 127. How do we not spec?
  • 128. describe User do it { Factory(:user).should have_many(:projects) } it { Factory(:user).should belong_to(:company) } table_has_columns(User, :string, quot;loginquot;) end class User has_many :projects belongs_to :company
  • 129. describe User do it { Factory(:user).should have_many(:projects) } it { Factory(:user).should belong_to(:company) } table_has_columns(User, :string, quot;loginquot;) end class User create_table quot;usersquot;, :force => true do |t| has_many :projects t.column :login, :string end belongs_to :company
  • 130. describe User do it { Factory(:user).should have_many(:projects) } it { Factory(:user).should belong_to(:company) } table_has_columns(User, :string, quot;loginquot;) end Structure is not interesting behavior! class User create_table quot;usersquot;, :force => true do |t| has_many :projects t.column :login, :string end belongs_to :company
  • 131. Progress Ideal Preso ✓ Estimating, Game, Burndown 20 100 ✓ Pair Programming 20 75 ✓ Acceptance vs Unit 20 50 Upfront Design 10 25 Love 10 0 Productivity 20 40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End! Total 100 Left: 40
  • 133.
  • 135. Progress Ideal Preso ✓ Estimating, Game, Burndown 20 100 ✓ Pair Programming 20 75 ✓ Acceptance vs Unit 20 50 ✓ Upfront Design 10 25 Love 10 0 Productivity 20 40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End! Total 100 Left: 30
  • 137.
  • 138.
  • 139. DRY Less code Skinny controller, fat model
  • 140. Technical debt DRY Less code Skinny controller, fat model
  • 141. Technical debt Broken windows DRY Less code Skinny controller, fat model
  • 142. Technical debt Broken windows DRY Less code Skinny controller, fat model Beautiful code
  • 143. Technical debt Broken windows DRY Less code Skinny controller, fat model Habitable software Beautiful code
  • 144. Technical debt Broken windows DRY Refactoring towards a deeper insight Less code Skinny controller, fat model Habitable software Beautiful code
  • 145. Progress Ideal Preso ✓ Estimating, Game, Burndown 20 100 ✓ Pair Programming 20 75 ✓ Acceptance vs Unit 20 50 ✓ Upfront Design 10 25 ✓ Love 10 0 Productivity 20 40’ 35’ 30’ 25’ 20’ 15’ 10’ 5’ End! Total 100 Left: 20
  • 147. You call that productivity?
  • 148.