Outside-In
                           Development
                               With




                            Ben ...
Who’s my
                           audience?



Saturday, March 14, 2009
Saturday, March 14, 2009
Scenario: planning meeting
      Given I am a Software Developer
      When I am given a feature request
      Then I shou...
What is the most
                           CRITICAL
   word to keep in mind?



Saturday, March 14, 2009
W
Saturday, March 14, 2009
Scenario: planning meeting
      Given I am a Software Developer
      When I am given a feature request
      Then I shou...
_why




Saturday, March 14, 2009
Why?
Saturday, March 14, 2009
Feature Request:
                      Print Reports
                Story from
                Thought works:

          ...
Saturday, March 14, 2009
Protect Revenue

                           Increase Revenue

                           Manage Cost


Saturday, March 14,...
* not executed
                           * documentation value

         Feature: title    * variant of contextra
       ...
There is no template.
          What is important to
          have in narrative:

           * business value
           ...
Scenario: title
              Given [Context]
              When I do [Action]
              Then I should see [Outcome]

...
Scenario: title
              Given [Context]
              And [More Context]
              When I do [Action]
          ...
project_root/
        |
        `-- features




Saturday, March 14, 2009
project_root/
        |
        `-- features
            |-- awesomeness.feature
            |-- greatest_ever.feature



...
project_root/
        |
        `-- features
            |-- awesomeness.feature
            |-- greatest_ever.feature
   ...
project_root/
        |
        `-- features
            |-- awesomeness.feature
            |-- greatest_ever.feature
   ...
Step

      Given a widget




Saturday, March 14, 2009
Step   Definition

                                  Given /^a widget$/ do
      Given a widget                #codes go he...
Step         Definition
                                  Step Mother

                                        Given /^a wi...
Step         Definition
                                  Step Mother

                                        Given /^a wi...
Outside-In


Saturday, March 14, 2009
Saturday, March 14, 2009
Saturday, March 14, 2009
Write Scenarios




Saturday, March 14, 2009
Steps are pending




Saturday, March 14, 2009
Write Step Definition




Saturday, March 14, 2009
Go Down A Gear




Saturday, March 14, 2009
RSpec




Saturday, March 14, 2009
RSpec

                           We ain’t got
                            no RSPEC!


Saturday, March 14, 2009
RSpec, TestUnit, etc




Saturday, March 14, 2009
Write Code Example
              (Unit Test)




Saturday, March 14, 2009
Make Example Pass




Saturday, March 14, 2009
REFACTOR!!



Saturday, March 14, 2009
Where Are we?




Saturday, March 14, 2009
Continue until...




Saturday, March 14, 2009
REFACTOR
                              and
                            REPEAT
Saturday, March 14, 2009
features/manage_my_wishes.feature
      Feature: manage my wishes

           In order to get more stuff
           As a g...
Saturday, March 14, 2009
Line # of scenario




Saturday, March 14, 2009
Saturday, March 14, 2009
I can has backtraze?
     Given I am logged in   #features/manage_my_wishes.feature:8




Saturday, March 14, 2009
Saturday, March 14, 2009
features/i_can_has_wishez_plz.feature


      OH HAI: I CAN HAS WISHEZ PLZ

           SO DAT I CAN HAS HUGS TIEM AN PLAY ...
Saturday, March 14, 2009
Saturday, March 14, 2009
cucumber some.feature --language en-lol




Saturday, March 14, 2009
cucumber some.feature --language en-lol




Saturday, March 14, 2009
Saturday, March 14, 2009
Saturday, March 14, 2009
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
                           Webrat / Awesomeness
      Given /^I am logged in$/ do
 ...
features/step_definitions/user_steps.rb
                           Webrat / Awesomeness
      Given /^I am logged in$/ do
 ...
features/step_definitions/user_steps.rb
                           Webrat / Awesomeness
      Given /^I am logged in$/ do
 ...
features/step_definitions/user_steps.rb
                           Webrat / Awesomeness
      Given /^I am logged in$/ do
 ...
features/step_definitions/user_steps.rb
                           Webrat / Awesomeness
      Given /^I am logged in$/ do
 ...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
Saturday, March 14, 2009
No route matches “/sessions/create” with
    {:method=>:post} (ActionController::RoutingError)




Saturday, March 14, 2009
I’m going to cheat...




Saturday, March 14, 2009
I’m going to cheat...
   $ gem install thoughtbot-clearance
   $ ./script generate clearance
   $ ./script generate cleara...
Saturday, March 14, 2009
features/step_definitions/wish_steps.rb
      When /^I make a quot;(.+)quot; wish$/ do |wish|

      end

      Then /^(.+)...
features/step_definitions/wish_steps.rb
      When /^I make a quot;(.+)quot; wish$/ do |wish|

      end

      Then /^(.+)...
features/step_definitions/wish_steps.rb
      When /^I make a quot;(.+)quot; wish$/ do |wish|
        visit quot;/wishesquo...
features/step_definitions/wish_steps.rb
      When /^I make a quot;(.+)quot; wish$/ do |wish|
        visit quot;/wishesquo...
features/step_definitions/wish_steps.rb
      When /^I make a quot;(.+)quot; wish$/ do |wish|
        visit quot;/wishesquo...
config/routes.rb
      ActionController::Routing::Routes.draw do |map|

           map.resources :wishes




Saturday, Marc...
config/routes.rb
      ActionController::Routing::Routes.draw do |map|

           map.resources :wishes



    When I make...
config/routes.rb
      ActionController::Routing::Routes.draw do |map|

           map.resources :wishes




  $./script ge...
config/routes.rb
      ActionController::Routing::Routes.draw do |map|

           map.resources :wishes




      When I m...
app/views/wishes/index.html.erb
      <%= link_to quot;Make a wishquot;, new_wish_path %>




Saturday, March 14, 2009
app/views/wishes/index.html.erb
      <%= link_to quot;Make a wishquot;, new_wish_path %>




     When I make a “New car”...
features/step_definitions/wish_steps.rb
      When /^I make a quot;(.+)quot; wish$/ do |wish|
        visit quot;/wishesquo...
features/step_definitions/wish_steps.rb
      When /^I make a quot;(.+)quot; wish$/ do |wish|
        visit quot;/wishesquo...
features/step_definitions/wish_steps.rb
      When /^I make a quot;(.+)quot; wish$/ do |wish|
        visit quot;/wishesquo...
View

                           Controller



Saturday, March 14, 2009
spec/controllers/wishes_controller_spec.rb
      describe WishesController do
        describe quot;POST / (#create)quot; ...
spec/controllers/wishes_controller_spec.rb
      describe WishesController do
        describe quot;POST / (#create)quot; ...
app/controllers/wishes_controller.rb
      class WishesController < ApplicationController

           def create
         ...
spec/controllers/wishes_controller_spec.rb
      describe WishesController do
        describe quot;POST / (#create)quot; ...
app/controllers/wishes_controller.rb
           def create
             current_user.wishes.create(params['wish'])
       ...
View

                           Controller

                             Model

Saturday, March 14, 2009
app/controllers/wishes_controller.rb
           def create
             current_user.wishes.create(params['wish'])
       ...
app/controllers/wishes_controller.rb
           def create
             current_user.wishes.create(params['wish'])
       ...
app/models/wish.rb
      class Wish < ActiveRecord::Base
        belongs_to :user
      end



      app/models/user.rb
  ...
app/models/wish.rb
      class Wish < ActiveRecord::Base
        belongs_to :user
      end



      app/models/user.rb
  ...
spec/controllers/wishes_controller_spec.rb
      it quot;should notify the user of creation via the flashquot; do
        ...
spec/controllers/wishes_controller_spec.rb
      it quot;should notify the user of creation via the flashquot; do
        ...
spec/controllers/wishes_controller_spec.rb
      it quot;should notify the user of creation via the flashquot; do
        ...
app/views/wishes/index.html.erb
      <ul>
      <% @wishes.each do |wish| %>
        <li><%= wish.name %></li>
      <% e...
spec/controllers/wishes_controller_spec.rb
           describe quot;GET / (#index)quot; do
             def do_get
       ...
app/controllers/wishes_controller.rb
           def index
             @wishes = current_user.wishes
           end




Sa...
Saturday, March 14, 2009
Saturday, March 14, 2009
Scenario: view members list
        Given the following wishes exist
          | Wish          | Family Member    |
      ...
Given the following   wishes exist
              | Wish          |   Family Member   |
              | Laptop        |   T...
Given the following   wishes exist
              | Wish          |   Family Member   |
              | Laptop        |   T...
Feature: Addition
        In order to avoid silly mistakes
        As a math idiot
        I want to be told the sum of tw...
Feature: Addition
        In order to avoid silly mistakes
        As a math idiot
        I want to be told the sum of tw...
Feature: Addition
        In order to avoid silly mistakes
        As a math idiot
        I want to be told the sum of tw...
Feature: Addition
        In order to avoid silly mistakes
        As a math idiot
        I want to be told the sum of tw...
Feature: Addition
        In order to avoid silly mistakes
        As a math idiot
        I want to be told the sum of tw...
Steps Within Steps
    When /^I view the wish list for quot;(.+)quot;$/ do |user_name|
      Given quot;I am logged inquot...
Steps Within Steps
    When /^I view the wish list for quot;(.+)quot;$/ do |user_name|
      Given quot;I am logged inquot...
Helpers - Ruby FTW
    When /^I view the wish list for quot;(.+)quot;$/ do |user_name|
      login_as(create_user)
      v...
Helpers - Ruby FTW
    When /^I view the wish list for quot;(.+)quot;$/ do |user_name|
      login_as(create_user)
      v...
features/step_definitions/user_steps.rb
      Given /^I am logged in$/ do
        @current_user = create_user(:email_confir...
features/step_definitions/user_steps.rb

      def login_as(user)
        visit new_session_path
        fill_in quot;Email...
features/step_definitions/user_steps.rb

      def login_as(user)
        visit new_session_path
        fill_in quot;Email...
features/step_definitions/user_steps.rb

      def login_as(user)
        visit new_session_path
        fill_in quot;Email...
features/step_definitions/user_steps.rb
      module UserHelpers
        def login_as(user)
          visit new_session_pat...
features/step_definitions/user_steps.rb
      module UserHelpers
        def login_as(user)
          visit new_session_pat...
features/step_definitions/user_steps.rb
      module UserHelpers
        def login_as(user)
          visit new_session_pat...
I can skp teh
              unit testz?




Saturday, March 14, 2009
Acceptance Tests                Unit Tests

                Application Level               Object Level- Isolated!
      ...
SRSLY?
       Model specs,
       Controller Specs,
       and view specs!?


Saturday, March 14, 2009
Saturday, March 14, 2009
Saturday, March 14, 2009
Saturday, March 14, 2009
W
Saturday, March 14, 2009
M
Saturday, March 14, 2009
More tests ==
                  More Maintenance




Saturday, March 14, 2009
Test Value =
                          Design +
                      Documentation +
                          Defence
  ...
if test.value > test.cost
      Suite.add(test)
    end




Saturday, March 14, 2009
KTHXBYE!
                           BenMabey.com
               github.com/bmabey
                           Twitter: bmab...
Upcoming SlideShare
Loading in...5
×

Outside In Development With Cucumber

1,673

Published on

0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,673
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
58
Comments
0
Likes
10
Embeds 0
No embeds

No notes for slide

Outside In Development With Cucumber

  1. 1. Outside-In Development With Ben Mabey Saturday, March 14, 2009
  2. 2. Who’s my audience? Saturday, March 14, 2009
  3. 3. Saturday, March 14, 2009
  4. 4. Scenario: planning meeting Given I am a Software Developer When I am given a feature request Then I should... Saturday, March 14, 2009
  5. 5. What is the most CRITICAL word to keep in mind? Saturday, March 14, 2009
  6. 6. W Saturday, March 14, 2009
  7. 7. Scenario: planning meeting Given I am a Software Developer When I am given a feature request Then I should ask why. Saturday, March 14, 2009
  8. 8. _why Saturday, March 14, 2009
  9. 9. Why? Saturday, March 14, 2009
  10. 10. Feature Request: Print Reports Story from Thought works: http:// www.theregister.co.uk/ 2007 /06/25/ Saturday, March 14, 2009
  11. 11. Saturday, March 14, 2009
  12. 12. Protect Revenue Increase Revenue Manage Cost Saturday, March 14, 2009
  13. 13. * not executed * documentation value Feature: title * variant of contextra * business value up front In order to [Business Value] As a [Role] I want to [Some Action] (feature) Saturday, March 14, 2009
  14. 14. There is no template. What is important to have in narrative: * business value * stakeholder role * user role * action to be taken by user Saturday, March 14, 2009
  15. 15. Scenario: title Given [Context] When I do [Action] Then I should see [Outcome] Saturday, March 14, 2009
  16. 16. Scenario: title Given [Context] And [More Context] When I do [Action] And [Other Action] Then I should see [Outcome] But I should not see [Outcome] Saturday, March 14, 2009
  17. 17. project_root/ | `-- features Saturday, March 14, 2009
  18. 18. project_root/ | `-- features |-- awesomeness.feature |-- greatest_ever.feature Saturday, March 14, 2009
  19. 19. project_root/ | `-- features |-- awesomeness.feature |-- greatest_ever.feature `-- support |-- env.rb `-- other_helpers.rb Saturday, March 14, 2009
  20. 20. project_root/ | `-- features |-- awesomeness.feature |-- greatest_ever.feature `-- support |-- env.rb `-- other_helpers.rb |-- step_definitions | |-- domain_concept_A.rb | `-- domain_concept_B.rb Saturday, March 14, 2009
  21. 21. Step Given a widget Saturday, March 14, 2009
  22. 22. Step Definition Given /^a widget$/ do Given a widget #codes go here end Saturday, March 14, 2009
  23. 23. Step Definition Step Mother Given /^a widget$/ do Given a widget #codes go here end Saturday, March 14, 2009
  24. 24. Step Definition Step Mother Given /^a widget$/ do Given a widget #codes go here end Saturday, March 14, 2009
  25. 25. Outside-In Saturday, March 14, 2009
  26. 26. Saturday, March 14, 2009
  27. 27. Saturday, March 14, 2009
  28. 28. Write Scenarios Saturday, March 14, 2009
  29. 29. Steps are pending Saturday, March 14, 2009
  30. 30. Write Step Definition Saturday, March 14, 2009
  31. 31. Go Down A Gear Saturday, March 14, 2009
  32. 32. RSpec Saturday, March 14, 2009
  33. 33. RSpec We ain’t got no RSPEC! Saturday, March 14, 2009
  34. 34. RSpec, TestUnit, etc Saturday, March 14, 2009
  35. 35. Write Code Example (Unit Test) Saturday, March 14, 2009
  36. 36. Make Example Pass Saturday, March 14, 2009
  37. 37. REFACTOR!! Saturday, March 14, 2009
  38. 38. Where Are we? Saturday, March 14, 2009
  39. 39. Continue until... Saturday, March 14, 2009
  40. 40. REFACTOR and REPEAT Saturday, March 14, 2009
  41. 41. features/manage_my_wishes.feature Feature: manage my wishes In order to get more stuff As a greedy person I want to manage my wish list for my family members to view Scenario: add wish Given I am logged in When I make a quot;New carquot; wish Then quot;New carquot; should appear on my wish list Saturday, March 14, 2009
  42. 42. Saturday, March 14, 2009
  43. 43. Line # of scenario Saturday, March 14, 2009
  44. 44. Saturday, March 14, 2009
  45. 45. I can has backtraze? Given I am logged in #features/manage_my_wishes.feature:8 Saturday, March 14, 2009
  46. 46. Saturday, March 14, 2009
  47. 47. features/i_can_has_wishez_plz.feature OH HAI: I CAN HAS WISHEZ PLZ SO DAT I CAN HAS HUGS TIEM AN PLAY TIEM AN SLEEP TIEM AN NOM TIEM AS NICE GREEDEE KITTEH I CAN PLZ MANEGE TEH WISHEZ MISHUN: MAK NEW WISH GIVN I AM LOGGD IN WEN I MAK quot;CHEEZBURGERquot; WISH DEN I C quot;CHEEZBURGERquot; ON ME WISHEZ LIT Saturday, March 14, 2009
  48. 48. Saturday, March 14, 2009
  49. 49. Saturday, March 14, 2009
  50. 50. cucumber some.feature --language en-lol Saturday, March 14, 2009
  51. 51. cucumber some.feature --language en-lol Saturday, March 14, 2009
  52. 52. Saturday, March 14, 2009
  53. 53. Saturday, March 14, 2009
  54. 54. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) end Saturday, March 14, 2009
  55. 55. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) end Test Data Builder / Object Mother Saturday, March 14, 2009
  56. 56. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) end Fixture Replacement, Fixjour, Factory Girl, etc spec/fixjour_builders.rb Fixjour do define_builder(User) do |klass, overrides| klass.new( :email => quot;user#{counter(:user)}@email.comquot;, :password => 'password', :password_confirmation => 'password' ) end end Saturday, March 14, 2009
  57. 57. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) end Saturday, March 14, 2009
  58. 58. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button end Saturday, March 14, 2009
  59. 59. features/step_definitions/user_steps.rb Webrat / Awesomeness Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button end Saturday, March 14, 2009
  60. 60. features/step_definitions/user_steps.rb Webrat / Awesomeness Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button end Saturday, March 14, 2009
  61. 61. features/step_definitions/user_steps.rb Webrat / Awesomeness Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button end features/support/env.rb require 'webrat' Webrat.configure do |config| config.mode = :rails end Saturday, March 14, 2009
  62. 62. features/step_definitions/user_steps.rb Webrat / Awesomeness Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button end features/support/env.rb require 'webrat' Webrat.configure do |config| config.mode = :rails end Adapter Saturday, March 14, 2009
  63. 63. features/step_definitions/user_steps.rb Webrat / Awesomeness Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button end features/step_definitions/webrat_steps.rb When /^I press quot;(.*)quot;$/ do |button| click_button(button) end 19 Steps Out-of-box When /^I follow quot;(.*)quot;$/ do |link| click_link(link) end When /^I fill in quot;(.*)quot; with quot;(.*)quot;$/ do |field, value| fill_in(field, :with => value) end Saturday, March 14, 2009
  64. 64. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button end Saturday, March 14, 2009
  65. 65. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not session[:user_id].should == @current_user.id end Saturday, March 14, 2009
  66. 66. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not session[:user_id].should == @current_user.id controller.current_user.should == @current_user end Saturday, March 14, 2009
  67. 67. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path Specify outcome, not implementation. fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not session[:user_id].should == @current_user.id controller.current_user.should == @current_user response.should contain(quot;Signed in successfullyquot;) end Saturday, March 14, 2009
  68. 68. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not response.should contain(quot;Signed in successfullyquot;) end Saturday, March 14, 2009
  69. 69. Saturday, March 14, 2009
  70. 70. No route matches “/sessions/create” with {:method=>:post} (ActionController::RoutingError) Saturday, March 14, 2009
  71. 71. I’m going to cheat... Saturday, March 14, 2009
  72. 72. I’m going to cheat... $ gem install thoughtbot-clearance $ ./script generate clearance $ ./script generate clearance_features Saturday, March 14, 2009
  73. 73. Saturday, March 14, 2009
  74. 74. features/step_definitions/wish_steps.rb When /^I make a quot;(.+)quot; wish$/ do |wish| end Then /^(.+) should appear on my wish list$/ do |wish| end Saturday, March 14, 2009
  75. 75. features/step_definitions/wish_steps.rb When /^I make a quot;(.+)quot; wish$/ do |wish| end Then /^(.+) should appear on my wish list$/ do |wish| end Regexp Capture -> Yielded Variable Saturday, March 14, 2009
  76. 76. features/step_definitions/wish_steps.rb When /^I make a quot;(.+)quot; wish$/ do |wish| visit quot;/wishesquot; click_link quot;Make a wishquot; fill_in quot;Wishquot;, :with => wish click_button end Then /^(.+) should appear on my wish list$/ do |wish| end Saturday, March 14, 2009
  77. 77. features/step_definitions/wish_steps.rb When /^I make a quot;(.+)quot; wish$/ do |wish| visit quot;/wishesquot; click_link quot;Make a wishquot; fill_in quot;Wishquot;, :with => wish click_button end Then /^(.+) should appear on my wish list$/ do |wish| response.should contain(quot;Your wish has been added!quot;) response.should contain(wish) end Saturday, March 14, 2009
  78. 78. features/step_definitions/wish_steps.rb When /^I make a quot;(.+)quot; wish$/ do |wish| visit quot;/wishesquot; click_link quot;Make a wishquot; fill_in quot;Wishquot;, :with => wish click_button end No route matches “/wishes” with {:method=>:get} appear on my wish list$/ do |wish| Then /^(.+) should (ActionController::RoutingError) response.should contain(quot;Your wish has been added!quot;) response.should contain(wish) end Saturday, March 14, 2009
  79. 79. config/routes.rb ActionController::Routing::Routes.draw do |map| map.resources :wishes Saturday, March 14, 2009
  80. 80. config/routes.rb ActionController::Routing::Routes.draw do |map| map.resources :wishes When I make a “New car” wish uninitialized constant WishesController (NameError) Saturday, March 14, 2009
  81. 81. config/routes.rb ActionController::Routing::Routes.draw do |map| map.resources :wishes $./script generate rspec_controller new create Saturday, March 14, 2009
  82. 82. config/routes.rb ActionController::Routing::Routes.draw do |map| map.resources :wishes When I make a “New car” wish Could not find link with text or title or id “Make a wish” (Webrat::NotFoundError) Saturday, March 14, 2009
  83. 83. app/views/wishes/index.html.erb <%= link_to quot;Make a wishquot;, new_wish_path %> Saturday, March 14, 2009
  84. 84. app/views/wishes/index.html.erb <%= link_to quot;Make a wishquot;, new_wish_path %> When I make a “New car” wish Could not find field: “Wish” (Webrat::NotFoundError) Saturday, March 14, 2009
  85. 85. features/step_definitions/wish_steps.rb When /^I make a quot;(.+)quot; wish$/ do |wish| visit quot;/wishesquot; click_link quot;Make a wishquot; fill_in quot;Wishquot;, :with => wish click_button end Saturday, March 14, 2009
  86. 86. features/step_definitions/wish_steps.rb When /^I make a quot;(.+)quot; wish$/ do |wish| visit quot;/wishesquot; click_link quot;Make a wishquot; fill_in quot;Wishquot;, :with => wish click_button end app/views/wishes/new.html.erb <% form_for :wish do |f| %> <%= f.label :name, quot;Wishquot; %> <%= f.text_field :name %> <%= submit_tag quot;Make the wish!quot; %> <% end %> Saturday, March 14, 2009
  87. 87. features/step_definitions/wish_steps.rb When /^I make a quot;(.+)quot; wish$/ do |wish| visit quot;/wishesquot; click_link quot;Make a wishquot; fill_in quot;Wishquot;, :with => wish click_button end Location Strategy FTW! app/views/wishes/new.html.erb <% form_for :wish do |f| %> <%= f.label :name, quot;Wishquot; %> <%= f.text_field :name %> <%= submit_tag quot;Make the wish!quot; %> <% end %> Saturday, March 14, 2009
  88. 88. View Controller Saturday, March 14, 2009
  89. 89. spec/controllers/wishes_controller_spec.rb describe WishesController do describe quot;POST / (#create)quot; do end end Saturday, March 14, 2009
  90. 90. spec/controllers/wishes_controller_spec.rb describe WishesController do describe quot;POST / (#create)quot; do it quot;should create a new wish for the user with the paramsquot; do user = mock_model(User, :wishes => mock(quot;wishes associationquot;)) controller.stub!(:current_user).and_return(user) user.wishes.should_receive(:create).with(wish_params) post :create, 'wish' => {'name' => 'Dog'} end end end Saturday, March 14, 2009
  91. 91. app/controllers/wishes_controller.rb class WishesController < ApplicationController def create current_user.wishes.create(params['wish']) end end Saturday, March 14, 2009
  92. 92. spec/controllers/wishes_controller_spec.rb describe WishesController do describe quot;POST / (#create)quot; do before(:each) do ..... it quot;should redirect the user to their wish listquot; do do_post response.should redirect_to(wishes_path) end end end Saturday, March 14, 2009
  93. 93. app/controllers/wishes_controller.rb def create current_user.wishes.create(params['wish']) redirect_to :action => :index end Saturday, March 14, 2009
  94. 94. View Controller Model Saturday, March 14, 2009
  95. 95. app/controllers/wishes_controller.rb def create current_user.wishes.create(params['wish']) redirect_to :action => :index end When I make a “New car” wish undefined method `wishes` for #<User:0x268e898> (NoMethodError) Saturday, March 14, 2009
  96. 96. app/controllers/wishes_controller.rb def create current_user.wishes.create(params['wish']) redirect_to :action => :index end $./script generate rspec_model wish name:string user_id:integer Saturday, March 14, 2009
  97. 97. app/models/wish.rb class Wish < ActiveRecord::Base belongs_to :user end app/models/user.rb class User < ActiveRecord::Base include Clearance::App::Models::User has_many :wishes end Saturday, March 14, 2009
  98. 98. app/models/wish.rb class Wish < ActiveRecord::Base belongs_to :user end app/models/user.rb When I make a “New car” wish Then “New <car” should appear on my wish class User ActiveRecord::Base include Clearance::App::Models::User has_many the following element’s content to include expected:wishes “Your wish has been added!” end Saturday, March 14, 2009
  99. 99. spec/controllers/wishes_controller_spec.rb it quot;should notify the user of creation via the flashquot; do do_post flash[:success].should == quot;Your wish has been added!quot; end Saturday, March 14, 2009
  100. 100. spec/controllers/wishes_controller_spec.rb it quot;should notify the user of creation via the flashquot; do do_post flash[:success].should == quot;Your wish has been added!quot; end app/controllers/wishes_controller.rb def create current_user.wishes.create(params['wish']) flash[:success] = quot;Your wish has been added!quot; redirect_to :action => :index end Saturday, March 14, 2009
  101. 101. spec/controllers/wishes_controller_spec.rb it quot;should notify the user of creation via the flashquot; do do_post flash[:success].should == quot;Your wish has been added!quot; end app/controllers/wishes_controller.rb Then “New car” should appear on my wish expected the following element’s content to include def create “New car” current_user.wishes.create(params['wish']) flash[:success] = quot;Your wish has been added!quot; redirect_to :action => :index end Saturday, March 14, 2009
  102. 102. app/views/wishes/index.html.erb <ul> <% @wishes.each do |wish| %> <li><%= wish.name %></li> <% end %> </ul> Saturday, March 14, 2009
  103. 103. spec/controllers/wishes_controller_spec.rb describe quot;GET / (#index)quot; do def do_get get :index end it quot;should assign the user's wishes to the viewquot; do do_get assigns[:wishes].should == @current_user.wishes end end Saturday, March 14, 2009
  104. 104. app/controllers/wishes_controller.rb def index @wishes = current_user.wishes end Saturday, March 14, 2009
  105. 105. Saturday, March 14, 2009
  106. 106. Saturday, March 14, 2009
  107. 107. Scenario: view members list Given the following wishes exist | Wish | Family Member | | Laptop | Thomas | | Nintendo Wii | Candace | | CHEEZBURGER | FuzzBuzz | When I view the wish list for quot;Candacequot; Then I should see the following wishes | Wish | | Nintendo Wii | Saturday, March 14, 2009
  108. 108. Given the following wishes exist | Wish | Family Member | | Laptop | Thomas | | Nintendo Wii | Candace | | CHEEZBURGER | FuzzBuzz | features/step_definitions/wish_steps.rb Given /^the following wishes exist$/ do |table| end end Saturday, March 14, 2009
  109. 109. Given the following wishes exist | Wish | Family Member | | Laptop | Thomas | | Nintendo Wii | Candace | | CHEEZBURGER | FuzzBuzz | features/step_definitions/wish_steps.rb Given /^the following wishes exist$/ do |table| table.hashes.each do |row| member = User.find_by_name(row[quot;Family Memberquot;]) || create_user(:name => row[quot;Family Memberquot;]) member.wishes.create!(:name => row[quot;Wishquot;]) end end Saturday, March 14, 2009
  110. 110. Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario Outline: Add two numbers Given I have entered <input_1> into the calculator And I have entered <input_2> into the calculator When I press <button> Then the result should be <output> on the screen Examples: | input_1 | input_2 | button | output | | 20 | 30 | add | 50 | |2 | 5 | add | 7 | |0 | 40 | add | 40 | Saturday, March 14, 2009
  111. 111. Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario Outline: Add two numbers Given I have entered <input_1> into the calculator And I have entered <input_2> into the calculator When I press <button> Then the result should be <output> on the screen Examples: | input_1 | input_2 | button | output | | 20 | 30 | add | 50 | |2 | 5 | add | 7 | |0 | 40 | add | 40 | Saturday, March 14, 2009
  112. 112. Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario Outline: Add two numbers Given I have entered <input_1> into the calculator And I have entered <input_2> into the calculator When I press <button> Then the result should be <output> on the screen Examples: | input_1 | input_2 | button | output | | 20 | 30 | add | 50 | |2 | 5 | add | 7 | |0 | 40 | add | 40 | Saturday, March 14, 2009
  113. 113. Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario Outline: Add two numbers Given I have entered <input_1> into the calculator And I have entered <input_2> into the calculator When I press <button> Then the result should be <output> on the screen Examples: | input_1 | input_2 | button | output | | 20 | 30 | add | 50 | |2 | 5 | add | 7 | |0 | 40 | add | 40 | Saturday, March 14, 2009
  114. 114. Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario Outline: Add two numbers Given I have entered <input_1> into the calculator And I have entered <input_2> into the calculator When I press <button> Then the result should be <output> on the screen Examples: | input_1 | input_2 | button | output | | 20 | 30 | add | 50 | |2 | 5 | add | 7 | |0 | 40 | add | 40 | Saturday, March 14, 2009
  115. 115. Steps Within Steps When /^I view the wish list for quot;(.+)quot;$/ do |user_name| Given quot;I am logged inquot; visit quot;/wishes/#{user_name}quot; end Saturday, March 14, 2009
  116. 116. Steps Within Steps When /^I view the wish list for quot;(.+)quot;$/ do |user_name| Given quot;I am logged inquot; visit quot;/wishes/#{user_name}quot; end Saturday, March 14, 2009
  117. 117. Helpers - Ruby FTW When /^I view the wish list for quot;(.+)quot;$/ do |user_name| login_as(create_user) visit quot;/wishes/#{user_name}quot; end Saturday, March 14, 2009
  118. 118. Helpers - Ruby FTW When /^I view the wish list for quot;(.+)quot;$/ do |user_name| login_as(create_user) visit quot;/wishes/#{user_name}quot; end Saturday, March 14, 2009
  119. 119. features/step_definitions/user_steps.rb Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) visit new_session_path fill_in quot;Emailquot;, :with => @current_user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button end Saturday, March 14, 2009
  120. 120. features/step_definitions/user_steps.rb def login_as(user) visit new_session_path fill_in quot;Emailquot;, :with => user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not response.should contain(quot;Signed in successfullyquot;) end Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) login_as(@current_user) end Saturday, March 14, 2009
  121. 121. features/step_definitions/user_steps.rb def login_as(user) visit new_session_path fill_in quot;Emailquot;, :with => user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not response.should contain(quot;Signed in successfullyquot;) end Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) login_as(@current_user) end Saturday, March 14, 2009
  122. 122. features/step_definitions/user_steps.rb def login_as(user) visit new_session_path fill_in quot;Emailquot;, :with => user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] “Every time you monkeypatch click_button # make sure we have actually logged in- so we fail fast if not Object, a kitten dies.” response.should contain(quot;Signed in successfullyquot;) end Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) login_as(@current_user) end http://seanohalpin.github.com/unobtrusive-metaprogramming/unobtrusive-metaprogramming.html Saturday, March 14, 2009
  123. 123. features/step_definitions/user_steps.rb module UserHelpers def login_as(user) visit new_session_path fill_in quot;Emailquot;, :with => user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not response.should contain(quot;Signed in successfullyquot;) end end Saturday, March 14, 2009
  124. 124. features/step_definitions/user_steps.rb module UserHelpers def login_as(user) visit new_session_path fill_in quot;Emailquot;, :with => user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not response.should contain(quot;Signed in successfullyquot;) end end Saturday, March 14, 2009
  125. 125. features/step_definitions/user_steps.rb module UserHelpers def login_as(user) visit new_session_path fill_in quot;Emailquot;, :with => user.email fill_in quot;Passwordquot;, :with => valid_user_attributes[quot;passwordquot;] click_button # make sure we have actually logged in- so we fail fast if not response.should contain(quot;Signed in successfullyquot;) end end World { |world| world.extend UserHelpers } Saturday, March 14, 2009
  126. 126. I can skp teh unit testz? Saturday, March 14, 2009
  127. 127. Acceptance Tests Unit Tests Application Level Object Level- Isolated! For Customers For developers Slow FAST! (should be at least) Good confidence - Tighter Feedback Loop Prevent against More about design!!!!!!!!!!!! regression Will need both gears! Some things are easier to test at the application level and vice-versa. Saturday, March 14, 2009
  128. 128. SRSLY? Model specs, Controller Specs, and view specs!? Saturday, March 14, 2009
  129. 129. Saturday, March 14, 2009
  130. 130. Saturday, March 14, 2009
  131. 131. Saturday, March 14, 2009
  132. 132. W Saturday, March 14, 2009
  133. 133. M Saturday, March 14, 2009
  134. 134. More tests == More Maintenance Saturday, March 14, 2009
  135. 135. Test Value = Design + Documentation + Defence (regression) Saturday, March 14, 2009
  136. 136. if test.value > test.cost Suite.add(test) end Saturday, March 14, 2009
  137. 137. KTHXBYE! BenMabey.com github.com/bmabey Twitter: bmabey IRC: mabes Saturday, March 14, 2009
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×