如果我有一个Devise模型User,其中只允许具有role:admin的用户查看某个url,我该如何编写RSpec集成测试来检查该url的状态是否返回200?
def login(user)
post user_session_path, :email => user.email, :password => 'password'
end
在这个问题的答案中,这是伪建议:Stubbing authentication in request spec,但我不能为我的生活让它与设计一起工作。 CanCan在检查Ability时收到一个nil用户,它自然没有正确的权限。
在集成规范中无法访问控制器,因此我无法存根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
答案 0 :(得分:47)
@ pschuegr自己的回答让我跨过了界限。为了完整起见,这就是我所做的,它让我轻松设置了请求规范和控制器规范(使用FactoryGirl创建用户实例):
#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'(使用FactoryGirl中的用户包装Devise :: TestHelpers sign_in方法)
答案 1 :(得分:28)
post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
答案 2 :(得分:20)
我使用了一种稍微不同的方法,使用Warden :: Test :: Helpers。
在我的spec / support / 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。
答案 3 :(得分:0)
您可以创建一个宏(/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
答案 4 :(得分:0)
我发现此链接非常有用https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)
答案 5 :(得分:0)
截至2017年中期,在我看来,我们还有一个更好的机会来整合我们的Rspecs设计。我们可以利用如下所述定义的辅助方法sign in
来利用存根验证:
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.rb
或rails_helper.rb
中附加新创建的文件:
require 'support/controller_helpers'
...
RSpec.configure do |config|
...
config.include Devise::TestHelpers, :type => :controller
config.include ControllerHelpers, :type => :controller
...
end
然后在方法中放置方法体sign_in
的开头,以获取经过身份验证的用户的上下文,并且您已完成设置。可以在设计文档here