在Rails 5控制器集成测试中设置cookie.signed

想象一下,有一个控制器集成测试调用控制器方法的场景,其中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设置。 上面的测试代码抛出exception:

NoMethodError:未定义的方法`签名’为Rack :: Test :: CookieJar:0x007fe90965ccd8

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

这似乎是Rails 5及更高版本中的一个已知错误 (链接的问题是关于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 signed cookie来获得所需的值(这个cookie jar 确实已经定义了signed方法,因为这是ActionDispatch::Cookies::CookieJar ,而不是Rack::Test::CookieJar )。 最后,通过在没有 signed访问者的情况下访问签名的cookie值检索签名的cookie值 ,并使用此值设置同名的测试cookie

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