如何使用RSpec和Devise / CanCan进行集成testing?

如果我有一个Devise模型用户,其中只有那些angular色:admin的用户才能查看某个url,那么如何编写RSpec集成testing来检查该url的状态是否返回200?

def login(user) post user_session_path, :email => user.email, :password => 'password' end 

这个问题在这个问题的答案中是伪build议的: 在请求规范中对authentication进行了stubbing ,但是我不能让它和devise一起工作。 CanCan在检查Ability时没有收到一个无用户,这个用户自然没有正确的权限。

在集成规范中没有对控制器的访问权限,所以我不能存根current_user,但我想要做这样的事情。

 describe "GET /users" do it "should be able to get" do clear_users_and_add_admin #does what it says... login(admin) get users_path response.status.should be(200) end end 

注意!!! :自问题提出以来所有这一切都改变了。 目前最好的方法是: http : //github.com/plataformatec/devise/wiki/How-To : -Test-with-Capybara

@ pschuegr自己的答案让我越过了界限。 为了完整性,这是我所做的,可以让我轻松设置请求规格和控制器规格(使用FactoryGirl创build用户实例):

在/spec/support/sign_in_support.rb中:

 #module for helping controller specs module ValidUserHelper def signed_in_as_a_valid_user @user ||= FactoryGirl.create :user sign_in @user # method from devise:TestHelpers end end # module for helping request specs module ValidUserRequestHelper # for use in request specs def sign_in_as_a_valid_user @user ||= FactoryGirl.create :user post_via_redirect user_session_path, 'user[email]' => @user.email, 'user[password]' => @user.password end end RSpec.configure do |config| config.include ValidUserHelper, :type => :controller config.include ValidUserRequestHelper, :type => :request end 

然后在请求规格:

 describe "GET /things" do it "test access to things, works with a signed in user" do sign_in_as_a_valid_user get things_path response.status.should be(200) end end describe "GET /things" do it "test access to things, does not work without a signed in user" do get things_path response.status.should be(302) # redirect to sign in page end end 

类似地,在控制器规范中使用“signed_in_as_valid_user”(将FactoryDe​​signer的用户包装在Devise :: TestHelpers的sign_in方法中)

啊,那么近。 这是诀窍 – 我错过了正确的参数forms,并redirect。

 post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password 

我用了一个稍微不同的方法,使用Warden :: Test :: Helpers。

在我的规格/支持/ macros.rb我补充说:

 module RequestMacros include Warden::Test::Helpers # for use in request specs def sign_in_as_a_user @user ||= FactoryGirl.create :confirmed_user login_as @user end end 

然后把它包含在RSpec的spec_helper.rb中:

 RSpec.configure do |config| config.include RequestMacros, :type => :request end 

然后在请求规格本身:

 describe "index" do it "redirects to home page" do sign_in_as_a_user visit "/url" page.should_not have_content 'content' end end 

post_via_redirect user_session_path方法相反,这实际上起作用,例如,允许我在before_filters中使用current_user。

你可以创build一个macros(/spec/support/controller_macros.rb)并写下如下内容:

 module ControllerMacros def login_user before(:each) do @request.env["devise.mapping"] = :user @user = Factory(:user) sign_in @user end end end 

你也可以包含你想要的任何CanCan属性。 那么,在你的规范中:

 describe YourController do login_user it "should ..." do end 

截至2017年年中,我认为我们还有更好的机会将devise融入我们的Rspecs。 我们能够利用辅助方法sign in来validation存根validation,定义如下:

 module ControllerHelpers def sign_in(user = double('user')) if user.nil? allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user}) allow(controller).to receive(:current_user).and_return(nil) else allow(request.env['warden']).to receive(:authenticate!).and_return(user) allow(controller).to receive(:current_user).and_return(user) end end end 

您还应该在spec_helper.rbrails_helper.rb引用中追加新创build的文件:

 require 'support/controller_helpers' ... RSpec.configure do |config| ... config.include Devise::TestHelpers, :type => :controller config.include ControllerHelpers, :type => :controller ... end 

然后在方法只是放置在方法身体sign_in的开始为authentication用户的上下文,你都设置。 最新的细节可以在devise文档中find