【问题标题】:Rails 5 - integration tests NoMethodError: undefined method `signed' for #<Rack::Test::CookieJar:0x00000006796390>Rails 5 - 集成测试 NoMethodError: undefined method `signed' for #<Rack::Test::CookieJar:0x00000006796390>
【发布时间】:2017-11-29 06:41:46
【问题描述】:

我一直在寻找解决方案很长时间,但我无法真正理解实际问题是什么。我正在关注 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 SessionsHelperActionDispatch::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

但是,因为测试 cookie jar 是 Rack::Test::CookieJar 这根本不起作用并引发 NoMethodError: undefined method 'signed' for #&lt;Rack::Test::CookieJar:0x00000006796390&gt;

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 分配给cookies 变量,即使我使用记住登录(对我来说这意味着使用cookies 而不是session),assert session[:user_id].nil? 也会失败。我正在努力解决这个问题,但这超出了我的能力范围。

编辑:

它变得越来越奇怪了。多次运行测试后,我似乎遇到了不同的错误。其中一些只是不时出现。

【问题讨论】:

  • 我无法检查您的代码,因为您添加了书中没有的行。我可以提供帮助的是一个 Bitbucket 存储库,其中包含整个教程的完整代码。我添加了更多测试,因此我的部分回购与本书不完全一致。你看到了什么错误;哪些测试失败了?如果你有一个回购,我可以把它拉下来并在这里复制错误,也许。
  • @OnlySteveH,对不起,我实际上重新实现了登录系统,以便它可以记住多个浏览器上的用户。这是带有我发布的代码的仓库:github.com/CosmicKid/LucidTracker/tree/account-activation 它有时会说缺少模板(但这与我现在要解决的问题并不真正相关),它还表明用户已登录(users_signup_test.rb :29)即使它没有被激活(但它可能是由于手动设置 cookie 而没有检查它是否被激活)。它也会在我提到的assert session[:user_id].nil? 上中断。
  • 不过,我基本上需要的是测试用户是否登录。唯一让它变得困难的是我无法真正测试cookies,因为Rack::Test::CookieJar 没有签名方法。
  • 我已经把它拉到了 c9 中。测试在第一次运行时失败,assert session[:user_id].nil? 行。我认为这是正确的——即使remember 设置为'0',会话也会有一个ID。但是,再次运行测试时,它们都是绿色的。我只在第一次运行时失败了。
  • 这里,“几乎”意味着我可能低估了session 的力量。昨天我修复了注销错误,该错误是由每次用户注销时重置会话引起的——事实证明,它不仅删除了用户的 id,而且还删除了与除GET 之外的所有 html 请求一起传递的特殊令牌。如果它如此重要,我可能应该将其作为用户 id 的存储并使用 cookies 仅用于记住用户 - 所以与教程中的方法相同。我会在决定更改登录系统之前尝试一下。

标签: ruby-on-rails cookies


【解决方案1】:

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

我决定浏览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,他通过提出一些有用的问题帮助了我。

【讨论】:

  • 很高兴你把它整理好了,我很高兴尝试和帮助。
猜你喜欢
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多