Ruby on rails Rails 5-集成测试命名错误:未定义的方法`signed';对于#<;机架::测试::CookieJar:0x00000006796390>;

Ruby on rails Rails 5-集成测试命名错误:未定义的方法`signed';对于#<;机架::测试::CookieJar:0x00000006796390>;,ruby-on-rails,cookies,Ruby On Rails,Cookies,我已经寻找解决方案很长时间了,但我不能真正理解实际的问题是什么。我正在学习MichaelHartl的RubyonRails教程,并尝试对登录进行一些集成测试。经过几次修改后,测试文件中的代码如下所示: test 'login without remembering' do login_as @user, remember: '1' delete logout_path login_as @user, remember: '0' assert_not session[:user_i

我已经寻找解决方案很长时间了,但我不能真正理解实际的问题是什么。我正在学习MichaelHartl的RubyonRails教程,并尝试对登录进行一些集成测试。经过几次修改后,测试文件中的代码如下所示:

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
class ActiveSupport::TestCase
  def logged_in?
    !session[:user_id].nil?
  end
end
logged\u in?
方法可通过
include sessionhelp
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
但是,因为test cookie jar是
Rack::test::CookieJar
这根本不起作用,并引发
NoMethodError:undefined方法“signed”for#

他帮我解决了这个问题。经过一段时间的思考,我做到了:

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
然而,我仍然不明白为什么它解决了我的问题,它是否是一个好的解决方案。如果我没有将cookie\u jar从请求的对象分配给
cookies
方法中的cookies变量,
assert session[:user\u id].nil?
即使我使用memory登录也会失败(对我来说,这意味着使用
cookies
而不是
session
)。我试着去想,但这超出了我的能力范围

编辑:


越来越奇怪了。在运行了几次测试之后,我似乎遇到了不同的错误。其中一些只是偶尔出现。

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

我决定仔细研究一下,发现我不需要在集成测试中尝试替换默认的cookie jar,而只需在helper测试中检查
cookies
。事实证明,在助手的测试中,cookie jar不是
Rack::Test::CookieJar
,而是
ActionDispatch::Cookies::CookieJar
,这很好,可以与
签名的方法一起工作。对于集成测试,我仅仅依赖于修改的
登录方法
只测试
会话[:user\u id]
,如下所示:

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
class ActiveSupport::TestCase
  def logged_in?
    !session[:user_id].nil?
  end
end
为了确保
cookies
有效,我为
sessionhelp
创建了一个合适的测试,可以在rails教程中找到

同样重要的是,我低估了
会话
。我决定将用户的id存储在那里,并将其作为用户登录的主要指示器,因此使用
cookies
仅用于记住用户。这样,我就不必担心在集成测试中测试
cookies
,这似乎是错误的


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

我无法检查您的代码,因为您添加了书中没有的行。我能帮助的是一个Bitbucket回购,它包含了整个教程中的完整代码。我增加了更多的测试,所以我的回购协议的一部分并不完全符合这本书。你看到了什么错误;哪些测试失败了?如果你有回购协议,我可以把它拉下来,在这里复制错误,也许。@OnlySteevh,对不起,我实际上已经重新实现了登录系统,以便它可以记住多个浏览器上的用户。下面是我发布的代码回复:它有时会说缺少一个模板(但这与我现在想要解决的问题无关),它还建议用户登录(users\u signup\u test.rb:29),即使它没有被激活(但可能是由于没有检查是否被激活而手动设置cookie造成的)。它还会在我提到的
assert session[:user\u id].nil?
上中断。不过,我基本上需要的是测试用户是否登录。唯一困难的是我不能真正测试
cookies
,因为
Rack::test::CookieJar
没有签名方法。我已经把它引入了c9。测试在第一次运行时失败,行
断言会话[:user\u id].nil?
。我认为这是正确的-即使
记住
设置为
'0'
,会话也会有一个id。但是,当再次运行测试时,它们都是绿色的。我只是在第一次运行时失败了。这里的“几乎”表示我可能低估了
会话的威力。昨天,我修复了因每次用户注销时重置会话而导致的注销错误-结果表明,它不仅删除了用户的id,而且还删除了与所有html请求一起传递的特殊令牌,除了
GET
。如果它如此重要,我可能应该依赖它作为用户id的存储,并使用
cookies
仅用于记住用户-与本教程中的方法相同。在我决定更改登录系统之前,我会尝试一下。很高兴你把它整理好了,我很高兴尝试并帮助你。