【问题标题】:Setup cookie.signed in Rails 5 controller integration tests在 Rails 5 控制器集成测试中设置 cookie.signed
【发布时间】:2017-09-27 04:44:27
【问题描述】:

想象一下有一个控制器集成测试调用一个控制器方法的场景,其中cookie.signed 用于一些完整性检查。

控制器

# app/controllers/foo_controller.rb

def index
  entity = FooEntity.find_by_id(params[:id])
  if entity.nil?
    raise ActionController::BadRequest, 'Could not find requested entity.'
  else
    @is_authorized = entity.token == cookies.signed[:token]
    if @is_authorized
      # Success! The path to be tested.
    else
      raise ActionController::BadRequest, 'Unauthorized cookie token.'
    end
  end
end

控制器测试

# app/test/controllers/foo_test.rb

require 'test_helper'

class FooControllerTest < ActionDispatch::IntegrationTest
  test 'should be working' do
    cookies.signed[:token] = '7e5201169ef160e31058d2a1976a5552'
    get '/foobar/123'
  end
end

但是,我不确定如何在测试中设置cookie.signed。上面的测试代码抛出异常:

NoMethodError: Rack::Test::CookieJar:0x007fe90965ccd8 的未定义方法“签名”

试图寻找解决方案,但我能找到的最接近的是这篇文章,https://sikac.hu/reconstruct-a-cookie-jar-and-read-signed-cookie-in-capybara-f71df387f9ff,但无法弄清楚如何构造 ActionDispatch::Request 对象。

【问题讨论】:

    标签: ruby-on-rails unit-testing cookies ruby-on-rails-5


    【解决方案1】:

    这似乎是 Rails 5 中的 known bug 及更高版本(链接的问题是关于 cookies.encrypted 但同样适用于 cookies.signed)。问题是在控制器测试中,cookie jar 是一个Rack::Test::CookieJar 类实例,它不支持签名/加密的 cookie。另一方面,在应用程序本身中,cookie jar 是一个ActionDispatch::Cookies::CookieJar 类实例,它支持这两种特殊的 cookie 类型。

    不过,要在控制器测试中构造一个签名的 cookie,您可以手动创建一个 ActionDispatch 请求 cookie jar 并使用它来检索签名的 cookie 值:

    # app/test/controllers/foo_test.rb
    
    require 'test_helper'
    
    class FooControllerTest < ActionDispatch::IntegrationTest
      test 'should be working' do
        my_cookies = ActionDispatch::Request.new(Rails.application.env_config.deep_dup).cookie_jar
        my_cookies.signed[:token] = '7e5201169ef160e31058d2a1976a5552'
    
        cookies[:token] = my_cookies[:token]
        get '/foobar/123'
      end
    end
    

    第一个测试行使用应用程序请求的默认环境设置创建一个新的ActionDispatch 请求(它们定义了例如用于签署 cookie 的秘密)并返回它的 cookie jar。然后,您只需将 :token 签名 cookie 设置为所需值(此 cookie jar 确实 定义了 signed 方法,因为这是 ActionDispatch::Cookies::CookieJar,而不是 Rack::Test::CookieJar)。最后,您通过signed 访问器访问它检索签名的cookie 值,并使用该值设置同名测试cookie

    现在,当测试到达控制器代码时,控制器应该会在 cookies.signed[:token] cookie 中看到正确的值。

    【讨论】:

    • 像魅力一样工作!感谢您的详细解释。非常感谢。
    • 更改 cookie 会影响Rails.application.env_config,这会泄露给其他测试用例。为避免这种情况,您可以改用保护性复制:Rails.application.env_config.deep_dup
    • 这样的解决方案正是我一直在寻找的,但我一辈子都无法让它发挥作用。无论我做什么,在请求期间都无法解析会话cookie。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多