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]

The RSpec Book: Behaviour Driven Development with RSpec, Cucumber, and Friends

You’ll get started right away with RSpec 2 and Cucumber by developing a simple game, using Cucumber to express high-level requirements in language your customer understands, and RSpec to express more granular requirements that focus on the behavior of individual objects in the system. You’ll learn how to use test doubles (mocks and stubs) to control the environment and focus the RSpec examples on one object at a time, and how to customize RSpec to „speak“ in the language of your domain.

You’ll develop Rails 3 applications and use companion tools such as Webrat and Selenium to express requirements for web applications both in memory and in the browser. And you’ll learn to specify Rails views, controllers, and models, each in complete isolation from the other.

Whether you’re developing applications, frameworks, or the libraries that power them, The RSpec Book will help you write better code, better tests, and deliver better software to happier users.