如何在Rails 3中测试cookies.permanent.signed

我在某个控制器中有一个动作,它在永久签名的cookie中设置了一些值,如下所示:

def some_action cookies.permanent.signed[:cookie_name] = "somevalue" end 

在一些function测试中,我正在尝试测试cookie是否设置正确起诉:

test "test cookies" do assert_equal "somevalue", cookies.permanent.signed[:cookie_name] end
test "test cookies" do assert_equal "somevalue", cookies.permanent.signed[:cookie_name] end 

但是,当我运行测试时,我收到以下错误:

NoMethodError: undefined method `permanent' for #
NoMethodError: undefined method `permanent' for # 

如果我只尝试:

test "test cookies" do assert_equal "somevalue", cookies.signed[:cookie_name] end
test "test cookies" do assert_equal "somevalue", cookies.signed[:cookie_name] end 

我明白了:

NoMethodError: undefined method `signed' for #
NoMethodError: undefined method `signed' for # 

如何在Rails 3中测试签名的cookie?

我在谷歌搜索类似问题的解决方案时遇到了这个问题,所以我将在这里发布。 我希望在测试控制器动作之前在Rspec中设置一个已签名的cookie。 以下工作:

 jar = ActionDispatch::Cookies::CookieJar.build(@request) jar.signed[:some_key] = "some value" @request.cookies['some_key'] = jar[:some_key] get :show ... 

请注意以下内容不起作用:

 # didn't work; the controller didn't see the signed cookie @request.cookie_jar.signed[:some_key] = "some value" get :show ... 

在rails 3的ActionControlller :: TestCase中,您可以在请求对象中设置签名的永久cookie,如下所示 –

  @request.cookies.permanent.signed[:foo] = "bar" 

并且可以通过执行此操作来测试从控制器中执行的操作返回的签名cookie

  test "do something" do get :index # or whatever jar = @request.cookie_jar jar.signed[:foo] = "bar" assert_equal jar[:foo], @response.cookies['foo'] #should both be some enc of 'bar' end 

请注意,我们需要设置signed cookie jar.signed[:foo] ,但是读取unsigned cookie jar[:foo] 。 只有这样我们才能获得在assert_equal进行比较所需的cookie的加密值。

在查看处理此问题的Rails代码之后,我为此创建了一个测试助手:

  def cookies_signed(name, opts={}) verifier = ActiveSupport::MessageVerifier.new(request.env["action_dispatch.secret_token".freeze]) if opts[:value] @request.cookies[name] = verifier.generate(opts[:value]) else verifier.verify(cookies[name]) end end 

将此添加到test_help.rb,然后您可以使用以下命令设置已签名的Cookie:

 cookies_signed(:foo, :value => 'bar') 

阅读它:

 cookies_signed(:foo) 

可能有点hackish,但它为我做的工作。

问题(至少在表面上)是在function测试(ActionController :: TestCase)的上下文中,“cookies”对象是哈希,而当你使用控制器时,它是一个ActionDispatch :: Cookies :: CookieJar对象。 所以我们需要将它转换为CookieJar对象,以便我们可以使用“signed”方法将其转换为SignedCookieJar。

您可以将以下内容放入function测试中(在获取请求之后)将Cookie从Hash转换为CookieJar对象

 @request.cookies.merge!(cookies) cookies = ActionDispatch::Cookies::CookieJar.build(@request) 

问题似乎也是你的测试。

下面是一些代码和测试,我用TDD来设置cookie的值,将params值传递给视图。

function测试:

 test "reference get set in cookie when visiting the site" do get :index, {:reference => "121212"} refute_nil cookies["reference"] end 

SomeController:

 before_filter :get_reference_code 

ApplicationController中:

 def get_reference_code cookies.signed[:reference] ||= params[:reference] end 

请注意,refute_nil行,cookie是一个字符串……这也是使得这个测试没有通过的一件事,就是在cookies[:reference]一个符号cookies[:reference]测试不喜欢那样,所以我没有这样做。