Outside-In Development With Cucumber

Preview:

DESCRIPTION

Cucumber is a BDD tool that aids in outside-in development by executing plain-text features/stories as automated acceptance tests. Written in conjunction with the stakeholder, these Cucumber “features” clearly articulate business value and also serve as a practical guide throughout the development process: by explicitly outlining the expected outcomes of various scenarios developers know both where to begin and when they are finished. I will present the basic usage of Cucumber, primarily in the context of web applications, which will include a survey of the common tools used for simulated and automated browser-testing. Common questions and pitfalls that arise will also be discussed.

Citation preview

With

Ben Mabey

Outside-In Development

Saturday, March 14, 2009

Who’s myaudience?

Saturday, March 14, 2009

Saturday, March 14, 2009

Scenario: planning meetingGiven I am a Software DeveloperWhen I am given a feature requestThen I should...

Saturday, March 14, 2009

What is the mostCRITICAL

word to keep in mind?

Saturday, March 14, 2009

WSaturday, March 14, 2009

Scenario: planning meetingGiven I am a Software DeveloperWhen I am given a feature requestThen I should ask why.

Saturday, March 14, 2009

_why

Saturday, March 14, 2009

Why?Saturday, March 14, 2009

Saturday, March 14, 2009

Protect Revenue

Increase Revenue

Manage Cost

Saturday, March 14, 2009

Feature: title

In order to [Business Value]As a [Role]I want to [Some Action] (feature)

* not executed* documentation value* variant of contextra* business value up front

Saturday, March 14, 2009

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

Scenario: titleGiven [Context]When I do [Action]Then I should see [Outcome]

Saturday, March 14, 2009

Scenario: titleGiven [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

project_root/| `-- features

Saturday, March 14, 2009

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

Saturday, March 14, 2009

project_root/| `-- features |-- awesomeness.feature |-- greatest_ever.feature `-- support |-- env.rb `-- other_helpers.rb

Saturday, March 14, 2009

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

Step

Given a widget

Saturday, March 14, 2009

Step

Given a widgetGiven /^a widget$/ do #codes go hereend

Definition

Saturday, March 14, 2009

Step

Given a widgetGiven /^a widget$/ do #codes go hereend

Definition

Step Mother

Saturday, March 14, 2009

Step

Given a widgetGiven /^a widget$/ do #codes go hereend

Definition

Step Mother

Saturday, March 14, 2009

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 gotno 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

REFACTORand

REPEAT

Saturday, March 14, 2009

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 "New car" wish Then "New car" should appear on my wish list

Saturday, March 14, 2009

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 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 "CHEEZBURGER" WISH DEN I C "CHEEZBURGER" ON ME WISHEZ LIT

Saturday, March 14, 2009

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_confirmed => true)

end

Saturday, March 14, 2009

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

features/step_definitions/user_steps.rb

Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true)

end

spec/fixjour_builders.rb

Fixjour do define_builder(User) do |klass, overrides| klass.new( :email => "user#{counter(:user)}@email.com", :password => 'password', :password_confirmation => 'password' ) endend

Fixture Replacement, Fixjour, Factory Girl, etc

Saturday, March 14, 2009

features/step_definitions/user_steps.rb

Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true)

end

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_buttonend

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_buttonend

Webrat / Awesomeness

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_buttonend

Webrat / Awesomeness

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_buttonend

features/support/env.rb

require 'webrat'

Webrat.configure do |config| config.mode = :railsend

Webrat / Awesomeness

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_buttonend

features/support/env.rb

require 'webrat'

Webrat.configure do |config| config.mode = :railsend

Adapter

Webrat / Awesomeness

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_buttonend

features/step_definitions/webrat_steps.rb

When /^I press "(.*)"$/ do |button| click_button(button)end

When /^I follow "(.*)"$/ do |link| click_link(link)end

When /^I fill in "(.*)" with "(.*)"$/ do |field, value| fill_in(field, :with => value) end

When /^I select "(.*)" from "(.*)"$/ do |value, field| select(value, :from => field) end

# Use this step in conjunction with Rail's datetime_select helper. For example:# When I select "December 25, 2008 10:00" as the date and time When /^I select "(.*)" as the date and time$/ do |time| select_datetime(time)end

# Use this step when using multiple datetime_select helpers on a page or # you want to specify which datetime to select. Given the following view:# <%= f.label :preferred %><br /># <%= f.datetime_select :preferred %># <%= f.label :alternative %><br /># <%= f.datetime_select :alternative %># The following steps would fill out the form:# When I select "November 23, 2004 11:20" as the "Preferred" data and time# And I select "November 25, 2004 10:30" as the "Alternative" data and timeWhen /^I select "(.*)" as the "(.*)" date and time$/ do |datetime, datetime_label| select_datetime(datetime, :from => datetime_label)end

# Use this step in conjunction with Rail's time_select helper. For example:# When I select "2:20PM" as the time# Note: Rail's default time helper provides 24-hour time-- not 12 hour time. Webrat# will convert the 2:20PM to 14:20 and then select it. When /^I select "(.*)" as the time$/ do |time| select_time(time)end

# Use this step when using multiple time_select helpers on a page or you want to# specify the name of the time on the form. For example:# When I select "7:30AM" as the "Gym" timeWhen /^I select "(.*)" as the "(.*)" time$/ do |time, time_label| select_time(time, :from => time_label)end

# Use this step in conjunction with Rail's date_select helper. For example:# When I select "February 20, 1981" as the dateWhen /^I select "(.*)" as the date$/ do |date| select_date(date)end

# Use this step when using multiple date_select helpers on one page or# you want to specify the name of the date on the form. For example:# When I select "April 26, 1982" as the "Date of Birth" dateWhen /^I select "(.*)" as the "(.*)" date$/ do |date, date_label| select_date(date, :from => date_label)end

When /^I check "(.*)"$/ do |field| check(field) end

When /^I uncheck "(.*)"$/ do |field| uncheck(field) end

When /^I choose "(.*)"$/ do |field| choose(field)end

When /^I attach the file at "(.*)" to "(.*)" $/ do |path, field| attach_file(field, path)end

Then /^I should see "(.*)"$/ do |text| response.should contain(text)end

Then /^I should not see "(.*)"$/ do |text| response.should_not contain(text)end

Then /^the "(.*)" checkbox should be checked$/ do |label| field_labeled(label).should be_checkedend

Webrat / Awesomeness

19 Steps Out-of-box

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_buttonend

Saturday, March 14, 2009

Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true)

visit new_session_path fill_in "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_button

end

features/step_definitions/user_steps.rb

Given /^I am logged in$/ do

# make sure we have actually logged in- so we fail fast if not session[:user_id].should == @current_user.idend

Saturday, March 14, 2009

features/step_definitions/user_steps.rb

Given /^I am logged in$/ do

# make sure we have actually logged in- so we fail fast if not controller.current_user.should == @current_userend

Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true)

visit new_session_path fill_in "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_button session[:user_id].should == @current_user.id

Saturday, March 14, 2009

Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true)

visit new_session_path fill_in "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_button

features/step_definitions/user_steps.rb

Given /^I am logged in$/ do

# 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("Signed in successfully")end

Specify outcome, not implementation.

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_button # make sure we have actually logged in- so we fail fast if not response.should contain("Signed in successfully")end

Saturday, March 14, 2009

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 clearance_features

Saturday, March 14, 2009

Saturday, March 14, 2009

features/step_definitions/wish_steps.rb

When /^I make a "(.+)" wish$/ do |wish| end

Then /^(.+) should appear on my wish list$/ do |wish| end

Saturday, March 14, 2009

features/step_definitions/wish_steps.rb

When /^I make a "(.+)" wish$/ do |wish| end

Then /^(.+) should appear on my wish list$/ do |wish| end

Regexp Capture -> Yielded Variable

Saturday, March 14, 2009

features/step_definitions/wish_steps.rb

When /^I make a "(.+)" wish$/ do |wish| visit "/wishes" click_link "Make a wish" fill_in "Wish", :with => wish click_buttonend

Then /^(.+) should appear on my wish list$/ do |wish| end

Saturday, March 14, 2009

features/step_definitions/wish_steps.rb

Then /^(.+) should appear on my wish list$/ do |wish| response.should contain("Your wish has been added!") response.should contain(wish)end

When /^I make a "(.+)" wish$/ do |wish| visit "/wishes" click_link "Make a wish" fill_in "Wish", :with => wish click_buttonend

Saturday, March 14, 2009

features/step_definitions/wish_steps.rb

When /^I make a "(.+)" wish$/ do |wish| visit "/wishes" click_link "Make a wish" fill_in "Wish", :with => wish click_buttonend

Then /^(.+) should appear on my wish list$/ do |wish| response.should contain("Your wish has been added!") response.should contain(wish)end

No route matches “/wishes” with{:method=>:get} (ActionController::RoutingError)

Saturday, March 14, 2009

config/routes.rb

ActionController::Routing::Routes.draw do |map| map.resources :wishes

Saturday, March 14, 2009

config/routes.rb

ActionController::Routing::Routes.draw do |map| map.resources :wishes

When I make a “New car” wishuninitialized constant WishesController (NameError)

Saturday, March 14, 2009

config/routes.rb

ActionController::Routing::Routes.draw do |map| map.resources :wishes

$./script generate rspec_controller new create

Saturday, March 14, 2009

config/routes.rb

ActionController::Routing::Routes.draw do |map| map.resources :wishes

When I make a “New car” wishCould not find link with text or title orid “Make a wish” (Webrat::NotFoundError)

Saturday, March 14, 2009

app/views/wishes/index.html.erb

<%= link_to "Make a wish", new_wish_path %>

Saturday, March 14, 2009

app/views/wishes/index.html.erb

<%= link_to "Make a wish", new_wish_path %>

When I make a “New car” wish Could not find field: “Wish” (Webrat::NotFoundError)

Saturday, March 14, 2009

features/step_definitions/wish_steps.rb

When /^I make a "(.+)" wish$/ do |wish| visit "/wishes" click_link "Make a wish" fill_in "Wish", :with => wish click_buttonend

Saturday, March 14, 2009

features/step_definitions/wish_steps.rb

When /^I make a "(.+)" wish$/ do |wish| visit "/wishes" click_link "Make a wish" fill_in "Wish", :with => wish click_buttonend

app/views/wishes/new.html.erb

<% form_for :wish do |f| %> <%= f.label :name, "Wish" %> <%= f.text_field :name %> <%= submit_tag "Make the wish!" %><% end %>

Saturday, March 14, 2009

fill_in "Wish", :with => wish

<%= f.label :name, "Wish" %> <%= f.text_field :name %>

features/step_definitions/wish_steps.rb

When /^I make a "(.+)" wish$/ do |wish| visit "/wishes" click_link "Make a wish" fill_in "Wish", :with => wish click_buttonend

app/views/wishes/new.html.erb

<% form_for :wish do |f| %> <%= submit_tag "Make the wish!" %><% end %>

Location Strategy FTW!

Saturday, March 14, 2009

View

Controller

Saturday, March 14, 2009

spec/controllers/wishes_controller_spec.rb

describe WishesController do describe "POST / (#create)" do

endend

Saturday, March 14, 2009

spec/controllers/wishes_controller_spec.rb

describe WishesController do describe "POST / (#create)" do it "should create a new wish for the user with the params" do user = mock_model(User, :wishes => mock("wishes association")) controller.stub!(:current_user).and_return(user) user.wishes.should_receive(:create).with(wish_params)

post :create, 'wish' => {'name' => 'Dog'} end endend

Saturday, March 14, 2009

app/controllers/wishes_controller.rb

class WishesController < ApplicationController

def create current_user.wishes.create(params['wish']) end

end

Saturday, March 14, 2009

spec/controllers/wishes_controller_spec.rb

it "should redirect the user to their wish list" do do_post response.should redirect_to(wishes_path) end

spec/controllers/wishes_controller_spec.rb

describe WishesController do describe "POST / (#create)" do before(:each) do .....

endend

Saturday, March 14, 2009

app/controllers/wishes_controller.rb

def create current_user.wishes.create(params['wish']) redirect_to :action => :index end

Saturday, March 14, 2009

View

Controller

Model

Saturday, March 14, 2009

app/controllers/wishes_controller.rb

def create current_user.wishes.create(params['wish']) redirect_to :action => :index end

When I make a “New car” wishundefined method `wishes` for #<User:0x268e898> (NoMethodError)

Saturday, March 14, 2009

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

app/models/wish.rb

class Wish < ActiveRecord::Base belongs_to :userend

app/models/user.rb

class User < ActiveRecord::Base include Clearance::App::Models::User has_many :wishesend

Saturday, March 14, 2009

app/models/wish.rb

class Wish < ActiveRecord::Base belongs_to :userend

app/models/user.rb

class User < ActiveRecord::Base include Clearance::App::Models::User has_many :wishesend

When I make a “New car” wishThen “New car” should appear on my wishexpected the following element’s content to include “Your wish has been added!”

Saturday, March 14, 2009

spec/controllers/wishes_controller_spec.rb

it "should notify the user of creation via the flash" do do_post flash[:success].should == "Your wish has been added!"end

Saturday, March 14, 2009

app/controllers/wishes_controller.rb

def create flash[:success] = "Your wish has been added!" end

spec/controllers/wishes_controller_spec.rb

it "should notify the user of creation via the flash" do do_post flash[:success].should == "Your wish has been added!"end

current_user.wishes.create(params['wish']) redirect_to :action => :index

Saturday, March 14, 2009

current_user.wishes.create(params['wish']) redirect_to :action => :index

app/controllers/wishes_controller.rb

def create flash[:success] = "Your wish has been added!" end

spec/controllers/wishes_controller_spec.rb

it "should notify the user of creation via the flash" do do_post flash[:success].should == "Your wish has been added!"end

Then “New car” should appear on my wishexpected the following element’s content to include “New car”

Saturday, March 14, 2009

app/views/wishes/index.html.erb

<ul><% @wishes.each do |wish| %> <li><%= wish.name %></li><% end %></ul>

Saturday, March 14, 2009

spec/controllers/wishes_controller_spec.rb

describe "GET / (#index)" do def do_get get :index end

it "should assign the user's wishes to the view" do do_get assigns[:wishes].should == @current_user.wishes end

end

Saturday, March 14, 2009

app/controllers/wishes_controller.rb

def index @wishes = current_user.wishes end

Saturday, March 14, 2009

Saturday, March 14, 2009

Saturday, March 14, 2009

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 "Candace"

Then I should see the following wishes | Wish | | Nintendo Wii |

Saturday, March 14, 2009

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|

endend

Saturday, March 14, 2009

| Wish | Family Member | features/step_definitions/wish_steps.rb

Given /^the following wishes exist$/ do |table| table.hashes.each do |row| member = User.find_by_name(row["Family Member"]) || create_user(:name => row["Family Member"])

member.wishes.create!(:name => row["Wish"]) endend

Given the following wishes exist | Wish | Family Member | | Laptop | Thomas | | Nintendo Wii | Candace | | CHEEZBURGER | FuzzBuzz |

Saturday, March 14, 2009

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

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 |

<input_1> <input_2> <button> <output>

| input_1 | input_2 | button | output |

Saturday, March 14, 2009

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 |

<input_1> <input_2> <button> <output>

| 20 | 30 | add | 50 |

Saturday, March 14, 2009

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 |

<input_1> <input_2> <button> <output>

| 2 | 5 | add | 7 |

Saturday, March 14, 2009

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 |

<input_1> <input_2> <button> <output>

| 0 | 40 | add | 40 |

Saturday, March 14, 2009

When /^I view the wish list for "(.+)"$/ do |user_name| Given "I am logged in" visit "/wishes/#{user_name}"end

Steps Within Steps

Saturday, March 14, 2009

When /^I view the wish list for "(.+)"$/ do |user_name| visit "/wishes/#{user_name}"end

Steps Within Steps Given "I am logged in"

Saturday, March 14, 2009

When /^I view the wish list for "(.+)"$/ do |user_name| login_as(create_user) visit "/wishes/#{user_name}"end

Helpers - Ruby FTW

Saturday, March 14, 2009

When /^I view the wish list for "(.+)"$/ do |user_name| visit "/wishes/#{user_name}"end

Helpers - Ruby FTW login_as(create_user)

Saturday, March 14, 2009

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 "Email", :with => @current_user.email fill_in "Password", :with => valid_user_attributes["password"] click_buttonend

Saturday, March 14, 2009

features/step_definitions/user_steps.rb

def login_as(user) visit new_session_path fill_in "Email", :with => user.email fill_in "Password", :with => valid_user_attributes["password"] click_button # make sure we have actually logged in- so we fail fast if not response.should contain("Signed in successfully") end Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) login_as(@current_user)end

Saturday, March 14, 2009

features/step_definitions/user_steps.rb

def login_as(user) visit new_session_path fill_in "Email", :with => user.email fill_in "Password", :with => valid_user_attributes["password"] click_button # make sure we have actually logged in- so we fail fast if not response.should contain("Signed in successfully") end Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) login_as(@current_user)end

Saturday, March 14, 2009

features/step_definitions/user_steps.rb

def login_as(user) visit new_session_path fill_in "Email", :with => user.email fill_in "Password", :with => valid_user_attributes["password"] click_button # make sure we have actually logged in- so we fail fast if not response.should contain("Signed in successfully") end Given /^I am logged in$/ do @current_user = create_user(:email_confirmed => true) login_as(@current_user)end

“Every time you monkeypatch Object, a kitten dies.”

http://seanohalpin.github.com/unobtrusive-metaprogramming/unobtrusive-metaprogramming.html

Saturday, March 14, 2009

features/step_definitions/user_steps.rb

module UserHelpers def login_as(user) visit new_session_path fill_in "Email", :with => user.email fill_in "Password", :with => valid_user_attributes["password"] click_button # make sure we have actually logged in- so we fail fast if not response.should contain("Signed in successfully") endend

Saturday, March 14, 2009

features/step_definitions/user_steps.rb

module UserHelpers def login_as(user) visit new_session_path fill_in "Email", :with => user.email fill_in "Password", :with => valid_user_attributes["password"] click_button # make sure we have actually logged in- so we fail fast if not response.should contain("Signed in successfully") endend

Saturday, March 14, 2009

features/step_definitions/user_steps.rb

World { |world| world.extend UserHelpers }

module UserHelpers def login_as(user) visit new_session_path fill_in "Email", :with => user.email fill_in "Password", :with => valid_user_attributes["password"] click_button # make sure we have actually logged in- so we fail fast if not response.should contain("Signed in successfully") endend

World { |world| world.extend UserHelpers }

Saturday, March 14, 2009

I can skp teh unit testz?

Saturday, March 14, 2009

Acceptance Tests

Application LevelFor CustomersSlowGood confidencePrevent against regression

Unit Tests

Object Level- Isolated!For developersFAST! (should be at least)- Tighter Feedback LoopMore about design!!!!!!!!!!!!

Will need both gears! Some things are easier to test at the application level and vice-versa.

Saturday, March 14, 2009

SRSLY?Model specs,Controller Specs,and view specs!?

Saturday, March 14, 2009

Saturday, March 14, 2009

Saturday, March 14, 2009

Saturday, March 14, 2009

WSaturday, March 14, 2009

MSaturday, March 14, 2009

More tests == More Maintenance

Saturday, March 14, 2009

Test Value =Design +

Documentation +Defence (regression)

Saturday, March 14, 2009

if test.value > test.cost Suite.add(test)end

Saturday, March 14, 2009

KTHXBYE!BenMabey.com

github.com/bmabey

Twitter: bmabeyIRC: mabes

Saturday, March 14, 2009

Recommended