outside-in development with cucumber
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.TRANSCRIPT
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
Feature Request:Print Reports
Story from Thoughtworks:
http://www.theregister.co.uk/2007/06/25/
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