我一直在使用 Devise 学习 Rails 3,到目前为止,它似乎运行良好。我有自定义会话和注册控制器,recaptcha 正在工作,登录用户可以通过 carrierwave 上传头像,该头像保存在 S3 上。对我的进步很满意。
现在我正在编写 Rspec 测试。没那么顺利!我有一个合理的用户模型测试,但那是因为我在网上找到了它(https://github.com/RailsApps/rails3-devise-rspec-cucumber/)并且能够通过跟随 Michael Hartl 的优秀“Ruby on Rails 3 教程”。
我真正的问题是控制器测试和集成测试,尤其是控制器测试。最初我以为我可以转换迈克尔书中的测试,我必须达到一个很小的程度,但进展缓慢,而且我似乎经常用头撞砖墙 - 我认为部分原因是因为我不我不太了解 Rspec 和 capybara(犯了一些非常愚蠢的错误),但也因为我对 Devise 的理解不够好,我想知道 Devise 是否能像 Rspec 一样出色地发挥作用;我在某处读到,因为 Devise 是基于 Rack 的,它可能并不总是像人们期望的那样使用 Rspec。不知道是真是假?
我知道有些人会想知道为什么这可能是必要的,因为 Devise 是一个 gem,因此已经过测试,但是我有几个例子,其他地方的更改在我没有立即意识到的情况下破坏了登录或注册。我认为一套好的控制器和集成测试可以解决这个问题。
如果我自己能够做到这一点,我会并且我会为其他人发布它,但到目前为止,编写这些测试非常痛苦,我真的需要继续做其他事情。
我敢肯定,我不会是唯一一个可以使用它的人。有人知道这样一套测试吗?
为了回应杰西的帮助...
这是我的registrations_controller_spec。“应该呈现'编辑'页面”中的评论显示了我正在努力解决的问题。此外,“应该创建一个用户”有一些我尝试过测试但无法做到的事情:
require File.dirname(__FILE__) + '/../spec_helper'
describe Users::RegistrationsController do
include Devise::TestHelpers
fixtures :all
render_views
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:user]
end
describe "POST 'create'" do
describe "failure" do
before(:each) do
@attr = { :email => "", :password => "",
:password_confirmation => "", :display_name => "" }
end
it "should not create a user" do
lambda do
post :create, :user_registration => @attr
end.should_not change(User, :count)
end
it "should render the 'new' page" do
post :create, :user_registration => @attr
response.should render_template('new')
end
end
describe "success" do
before(:each) do
@attr = { :email => "user@example.com",
:password => "foobar01", :password_confirmation => "foobar01", :display_name => "New User" }
end
it "should create a user" do
lambda do
post :create, :user => @attr
response.should redirect_to(root_path)
#response.body.should have_selector('h1', :text => "Sample App")
#response.should have_css('h1', :text => "Sample App")
#flash[:success].should == "A message with a confirmation link has been sent to your email address. Please open the link to activate your account."
#response.should have_content "A message with a confirmation link has been sent to your email address. Please open the link to activate your account."
end.should change(User, :count).by(1)
end
end
end
describe "PUT 'update'" do
before(:each) do
@user = FactoryGirl.create(:user)
@user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
sign_in @user
end
describe "Failure" do
before(:each) do
# The following information is valid except for display_name which is too long (max 20 characters)
@attr = { :email => @user.email, :display_name => "Test", :current_password => @user.password }
end
it "should render the 'edit' page" do
put :update, :id => subject.current_user, :user => @attr
# HAVE PUT THE DEBUGS THAT I'D LIKE TO GET WORKING FIRST
# Would like to be able to debug and check I'm getting the error(s) I'm expecting
puts subject.current_user.errors.messages # doesn't show me the errors
# Would like to be able to debug what html is being returned:
puts page.html # only return the first line of html
# Would like to be able to determine that this test is failing for the right reasons
response.should have_content "Display name is too long (maximum is 20 characters)" # doesn't work
response.should render_template('edit')
end
end
describe "Success" do
it "should change the user's display name" do
@attr = { :email => @user.email, :display_name => "Test", :current_password => @user.password }
put :update, :id => subject.current_user, :user => @attr
subject.current_user.reload
response.should redirect_to(root_path)
subject.current_user.display_name == @attr[:display_name]
end
end
end
describe "authentication of edit/update pages" do
describe "for non-signed-in users" do
before(:each) do
@user = FactoryGirl.create(:user)
end
describe "for non-signed-in users" do
it "should deny access to 'edit'" do
get :edit, :id => @user
response.should redirect_to(new_user_session_path)
end
it "should deny access to 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(new_user_session_path)
end
end
end
end
end