【发布时间】:2011-08-11 21:52:34
【问题描述】:
我有一个带有 Devise 和 CanCan 的 Rails 3.1 (RC5) 应用程序。两者都配置良好并且按预期工作,除了当我运行集成测试以确保根据需要重定向 AccessDenied 时,重定向转到 Devise 的登录而不是应用程序根目录。我可以在我的测试中验证用户仍然登录并且仍然可以访问应用程序的适用部分。
重定向在这个短控制器中定义,其他受限控制器继承(而不是直接继承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) 集成测试;我仅有的额外测试宝石是 Capybara、Machinist 和 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
我在测试中混合了 Capybara 访问方法(visit、click_button 等)和 vanilla 集成测试访问方法(get 等)。当我使用 Webrat(在 Capybara 之前)时,这种混合按我的预期工作,但显然 Capybara 的会话状态是单独处理的,因此通过 Capybara 方法的访问是经过身份验证的,但通过 vanilla 集成测试方法的访问不是。
【问题讨论】:
-
您是否仔细检查了是否调用了rescue_from CanCan::AccessDenied 块?
-
这基本上就是重点 - 它没有在测试环境中被调用。为了验证这一点,我在rescue_from块中添加了一个日志语句(在重定向之前),它在运行我的集成测试时没有出现在测试日志中,但它确实出现在了开发日志中。
标签: ruby-on-rails devise integration-testing cancan