我有一个Rails 3.1 (RC5)应用程序与设计和CanCan。两者都配置得很好,并且都像预期的那样工作,除了当我运行集成测试以确保AccessDenied按预期重定向时,重定向到设计的登录而不是应用程序根。我可以在我的测试中验证用户仍然登录并且仍然可以访问应用程序的适用部分。
重定向是在这个短控制器中定义的,它被其他受限制的控制器继承(而不是直接继承ApplicationController)。
class AuthorizedController < ApplicationController
before_filter :authenticate_user!
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
end
end
受限制的控制器如下所示:
class Admin::UsersController < AuthorizedController
load_and_authorize_resource
def index
@users = User.all.order('name')
end
...
end
我使用默认的(ActionDispatch::IntegrationTest)集成测试;我唯一拥有的额外测试宝石是水豚,机械师和Faker(没有RSpec, Cucumber等)。
我的测试如下:
def test_user_permissions
sign_in users(:user)
get admin_users_path
assert_response :redirect
assert_redirected_to root_url
end
测试失败:
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/users/sign_in>
当我在开发环境中作为受限用户登录进行测试时,我被重定向到'/',但在集成测试中使用相同类型的用户失败。
在集成测试中,用户实际上并没有注销,尽管重定向使它看起来像是正在发生。当我将测试更改为不测试重定向目标并继续尝试其他url时,用户仍然登录并且测试通过。
附录,解决方案:
我最初没有包括保存关键线索的sign_in方法。
module ActionController
class IntegrationTest
include Capybara::DSL
def sign_in (user, password = 'Passw0rd')
sign_out
visit root_path
fill_in 'Email', :with => user.email
fill_in 'Password', :with => password
click_button 'Sign in'
signed_in? user
end
...
end
end
我在sign_in
中混合了Capybara接入方法(visit
、click_button
等)和vanilla集成测试接入方法(get
等)。当我使用Webrat(在Capybara之前)时,这种混合工作如我所料,但显然Capybara的会话状态是单独处理的,因此通过Capybara方法的访问是经过身份验证的,但通过香草集成测试方法的访问不是。
您没有在ApplicationController中发布您的设计配置,但看起来设计身份/登录检查在CanCan授权检查(这是有意义的)之前加载。
看起来你的测试登录设置不正确,因为'/users/sign_in'是当没有有效的用户会话时,设备的默认重定向。
因为设计身份检查失败,它永远不会击中你的CanCan授权检查。如果还没有用户,为什么要问用户能做什么呢?
before_filters将按照它们被定义的顺序首先从基ApplicationController执行,所以子类过滤器在基类过滤器之后。这就是为什么我认为你在你的基础ApplicationController中有设计配置,导致它不击中CanCan。
如果你张贴你的设计配置/代码,我们可以帮助你进一步调试它。
EDIT/TLDR:
你看到一个重定向到登录,因为设计不认为一个有效的用户会话存在。您的测试"sign_in()"帮助器没有按照您想象的方式工作。