Rails 5 - 集成测试NoMethodError:未定义的方法`signed' ##rack :: test :: cookiejar:0x00000006796390>

时间:2017-11-27 11:59:21

标签: ruby-on-rails cookies

我一直在寻找解决方案很长一段时间,但我无法真正理解实际问题是什么。我正在跟随Michael Hartl的Ruby On Rails教程并尝试为登录进行一些集成测试。经过一些修改后,测试文件中的代码如下所示:

test 'login without remembering' do
  login_as @user, remember: '1'
  delete logout_path
  login_as @user, remember: '0'
  assert_not session[:user_id].nil?
  assert_nil cookies[:remember_token]
  assert_nil cookies[:user_id]
end

test 'login with remembering' do
  login_as @user, remember: '1'
  assert logged_in?
  assert_not_empty cookies[:remember_token]
  assert_not_empty cookies[:user_id]
  assert session[:user_id].nil?
  assert_equal assigns(:user).remember_token, cookies[:remember_token]
end

logged_in?方法可由include SessionsHelper中的ActionDispatch::IntegrationTest获取。它的核心部分是找到一个用户:

if (user_id = session[:user_id]) # User is not remembered
  @current_user = User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id]) # User is remembered
  user = User.find_by(id: user_id)
  remember_token = cookies[:remember_token]
  (@current_user = user) if user && user.authenticated?(remember_token)
end

但是,因为测试饼干罐是Rack::Test::CookieJar,这根本不起作用并引发NoMethodError: undefined method 'signed' for #<Rack::Test::CookieJar:0x00000006796390>

This非常有用并帮助我解决了这个问题。经过一段时间的思考,我做到了:

class ActionDispatch::IntegrationTest
  # Get ActionDispatch::Cookies::CookieJar because Rack::Test::CookieJar
  # doesn't support signed cookies
  def cookies
    cookies = ActionDispatch::Request.new(Rails.application.env_config).cookie_jar
  end

  include SessionsHelper

  def login_as(user, password: 'Password', remember: '0')
    post login_path, params: { session: { email: user.email,
                                          password: password,
                                          remember: remember } }

    # Set cookies manually
    return if remember == '0'
    user = assigns(:user)
    return if user.remember_token.nil?
    cookies[:remember_token] = user.remember_token
    cookies.signed[:user_id] = user.id
  end
end

但是,我仍然不明白为什么它能解决我的问题以及它是否是一个好的解决方案。如果我没有在cookies方法中将请求对象的cookie_jar分配给cookie变量,即使我使用记住登录,assert session[:user_id].nil?也会失败(对我而言,这意味着使用cookies代替{ {1}})。我试图绕过它,但这超出了我的能力。

修改

它越来越怪异了。看起来我多次运行测试后会遇到不同的错误。其中一些只是不时出现。

1 个答案:

答案 0 :(得分:0)

嗯,这些修改都没有解决我的问题,说实话,我的一些测试开始表现不一致。

我决定翻阅Ruby On Rails Tutorial,发现在集成测试中我没有尝试替换默认的cookie jar,而是在辅助测试中检查cookies。事实证明,在帮助测试中,cookie jar不是Rack::Test::CookieJar而是ActionDispatch::Cookies::CookieJar,这很好并且可以使用signed方法。对于集成测试,我只依靠修改后的logged_in?方法,该方法仅测试session[:user_id],如下所示:

class ActiveSupport::TestCase
  def logged_in?
    !session[:user_id].nil?
  end
end

为了确保cookies有效,我为SessionsHelper创建了一个合适的测试,可以在rails教程中找到。

同样重要的是我低估了session。我决定在那里存储用户ID,并将其视为用户登录的主要指示符,从而仅使用cookies来记住用户。通过这种方式,我不必担心在集成测试中测试cookies,这似乎是错误的。

非常感谢OnlySteveH通过提出一些有用的问题来帮助我。