使用Devise运行Rake控制器测试遇302重定向,如何在测试前登录?
你遇到的问题很典型——因为CustomersController的index动作需要用户登录才能访问,而你的测试代码里没有执行登录步骤,所以被Devise自动重定向到了登录页面,导致测试断言2XX成功响应失败,实际得到302重定向。
先回顾下你的错误信息:
Failure: CustomersControllerTest#test_should_get_index [/home/ubuntu/workspace/test/controllers/customers_controller_test.rb:7]: Expected response to be a <2XX: success>, but was a <302: Found> redirect to http://www.example.com/users/sign_in Response body: You are being redirected.
以及你的测试代码:
test "should get index" do get customers_url assert_response :success end
下面是具体的解决方法:
1. 在测试中创建/获取用户
首先你需要一个可用的测试用户,推荐直接在测试代码里创建(测试环境数据库是独立的,种子数据可能不会自动加载):
# 创建一个符合验证规则的用户 user = User.create!( email: 'test_customer@example.com', password: 'secure_password_123', password_confirmation: 'secure_password_123' )
如果一定要用你之前的种子数据,记得先在测试环境执行rake db:seed,不过测试环境每次运行测试可能会重置数据库,所以在测试里创建用户更稳定。
2. 使用Devise的sign_in辅助方法登录
Devise专门为测试提供了sign_in辅助方法,你可以在访问页面之前调用它来登录用户,修改后的测试代码如下:
test "should get index" do # 创建测试用户 user = User.create!( email: 'test_customer@example.com', password: 'secure_password_123', password_confirmation: 'secure_password_123' ) # 登录用户 sign_in user # 访问客户列表页面 get customers_url # 断言响应成功 assert_response :success end
3. 优化:用setup方法复用登录逻辑
如果你的控制器测试有多个用例都需要登录,可以把用户创建和登录逻辑放到setup方法里,避免重复代码:
class CustomersControllerTest < ActionDispatch::IntegrationTest setup do # 每次测试前创建并登录用户 @user = User.create!( email: 'test_customer@example.com', password: 'secure_password_123', password_confirmation: 'secure_password_123' ) sign_in @user end test "should get index" do get customers_url assert_response :success end # 其他需要登录的测试用例... end
这样修改后,你的测试就能正常访问需要登录的页面,不会再被重定向到登录页了。
内容的提问来源于stack exchange,提问作者Cannon Moyer

