Screencast: Testen von Password-Reset und Erinnerung

In der letzten Woche zeigte Ryan wie man selber eine Funktion zum Zurücksetzen von Passwörter bauen kann. In dieser Woche zeigt er wie er diese Funktion mit RSpec, Capybara, Factory Girl und Guard testet.

 

Downloads in verschiedenen Formaten:

source code
mp4
m4v
webm
ogv

 

Resourcen:

bash

[bash]
bundle rails g rspec:install mkdir spec/support spec/models spec/routing guard init rspec gem install rb-fsevent rails g integration_test password_reset rails g controller password_resets new –no-test-framework rails g mailer user_mailer password_reset rails g migration add_password_reset_to_users password_reset_token:string password_reset_sent_at:datetime rake db:migrate
[/bash]

Gemfile

[ruby]
gem "rspec-rails", :group => [:test, :development] group :test do gem "factory_girl_rails" gem "capybara" gem "guard-rspec" end
[/ruby]

spec_helper.rb

[ruby]
require ‚capybara/rspec‘ RSpec.configure do |config| # … config.include(MailerMacros) config.before(:each) { reset_email } end
[/ruby]

spec/support/mailer_macros.rb

[ruby]
module MailerMacros def last_email ActionMailer::Base.deliveries.last end def reset_email ActionMailer::Base.deliveries = [] end end
[/ruby]

config/environments/test.rb

[ruby]
config.action_mailer.default_url_options = { :host => "www.example.com" }
[/ruby]

spec/requests/password_resets_spec.rb

[ruby]
describe "PasswordResets" do it "emails user when requesting password reset" do user = Factory(:user) visit login_path click_link "password" fill_in "Email", :with => user.email click_button "Reset Password" current_path.should eq(root_path) page.should have_content("Email sent") last_email.to.should include(user.email) end it "does not email invalid user when requesting password reset" do visit login_path click_link "password" fill_in "Email", :with => "nobody@example.com" click_button "Reset Password" current_path.should eq(root_path) page.should have_content("Email sent") last_email.should be_nil end it "updates the user password when confirmation matches" do user = Factory(:user, :password_reset_token => "something", :password_reset_sent_at => 1.hour.ago) visit edit_password_reset_path(user.password_reset_token) fill_in "Password", :with => "foobar" click_button "Update Password" page.should have_content("Password doesn’t match confirmation") fill_in "Password", :with => "foobar" fill_in "Password confirmation", :with => "foobar" click_button "Update Password" page.should have_content("Password has been reset") end it "reports when password token has expired" do user = Factory(:user, :password_reset_token => "something", :password_reset_sent_at => 5.hour.ago) visit edit_password_reset_path(user.password_reset_token) fill_in "Password", :with => "foobar" fill_in "Password confirmation", :with => "foobar" click_button "Update Password" page.should have_content("Password reset has expired") end it "raises record not found when password token is invalid" do lambda { visit edit_password_reset_path("invalid") }.should raise_exception(ActiveRecord::RecordNotFound) end end
[/ruby]

spec/models/user_spec.rb

[ruby]
describe User do describe "#send_password_reset" do let(:user) { Factory(:user) } it "generates a unique password_reset_token each time" do user.send_password_reset last_token = user.password_reset_token user.send_password_reset user.password_reset_token.should_not eq(last_token) end it "saves the time the password reset was sent" do user.send_password_reset user.reload.password_reset_sent_at.should be_present end it "delivers email to user" do user.send_password_reset last_email.to.should include(user.email) end end end
[/ruby]

spec/mailers/user_mailer_spec.rb

[ruby]
describe UserMailer do describe "password_reset" do let(:user) { Factory(:user, :password_reset_token => "anything") } let(:mail) { UserMailer.password_reset(user) } it "send user password reset url" do mail.subject.should eq("Password Reset") mail.to.should eq([user.email]) mail.from.should eq(["from@example.com"]) mail.body.encoded.should match(edit_password_reset_path(user.password_reset_token)) end end end
[/ruby]

Request Specs und Capybara

Request specs in RSpec sind einge großartige Möglichkeit den kompletten Applikation-Stack zu testen. Ryan zeigt diese Woche wie dies und capybara in Verbindung mit Selenium eingesetzt werden kann.

 

Download:

Download(20.3 MB, 13:16)
Alternativer Download für iPod & Apple TV(20.6 MB, 13:16)

 

Resourcen:

 

Quellcode:

[bash]
bundle
rails g rspec:install
rails g integration_test task
rake spec:requests
[/bash]

[ruby]
# Gemfile
group :development, :test do
gem ‚rspec-rails‘
gem ‚capybara‘, :git => ‚git://github.com/jnicklas/capybara.git‘
gem ‚launchy‘
gem ‚database_cleaner‘
end

# spec/requests/tasks_spec
describe "Tasks" do
describe "GET /tasks" do
it "displays tasks" do
Task.create!(:name => "paint fence")
visit tasks_path
page.should have_content("paint fence")
end

it "supports js", :js => true do
visit tasks_path
click_link "test js"
page.should have_content("js works")
end
end

describe "POST /tasks" do
it "creates task" do
visit tasks_path
fill_in "New Task", :with => "mow lawn"
click_button "Add"
page.should have_content("Successfully added task.")
page.should have_content("mow lawn")
end
end
end

# spec_helper.rb
require ‚capybara/rspec‘

RSpec.configure do |config|
# …
config.use_transactional_fixtures = false

config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end

config.before(:each) do
DatabaseCleaner.start
end

config.after(:each) do
DatabaseCleaner.clean
end
end
[/ruby]

[html]
<!– tasks/index.html.erb –>
<%= link_to_function "test js", ‚$(this).html("js works")‘ %>
[/html]