如何在Rails 3中测试带签名的永久Cookies

18

我有一个控制器中的操作,可以像这样在永久签名的cookie中设置一些值:


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

在一些功能测试中,我试图通过以下方式测试Cookie是否被正确设置:


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

然而,当我运行测试时,出现了以下错误:

NoMethodError: undefined method `permanent' for # 无法定义方法`permanent`的错误。

如果我只尝试:

测试 "测试cookies" 块: 断言相等 "somevalue", cookies.signed [:cookie_name] 结束

I get:


NoMethodError: undefined method `signed' for #

在Rails 3中如何测试已签名的cookies?
5个回答

18

我在谷歌搜索类似问题的解决方案时发现了这个问题,所以我会在此处发布。我希望在测试控制器动作之前在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 ...

我刚刚遇到了这个问题,但是通过这个方法完美地解决了它。然而需要注意的是,我必须将代码中的:@request.cookies[:some_key]改为:@request.cookies["some_key"] - Atiaxi
太棒了,balexand。我希望我能给你10个大拇指。 - allesklar
@Atiaxi,我使用的是Rails 3.2.12版本,我可以使用符号来访问@request.cookies [:some_key] = jar [:some_key]。 - Gerry Shaw
原始问题是关于查看响应Cookie,而不是请求Cookie。 - Mathieu J.
Rspec在这里解释了引用cookies时字符串和符号的区别:https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs/cookies - Chris Beck

8
在Rails 3的ActionController::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 

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

太棒了!我只是使用:@request.cookie_jar.signed[:foo] = 'bar' - Trevor Turk

7

在查看处理此问题的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)

也许有点取巧,但对我来说可以完成工作。

干得好,我已经将该方法重命名为#signed_cookie,并将其放入一个模块中以混合到控制器规范中。有关参考,请参见此gist - Kenneth Kalmer

2
在功能测试(ActionController::TestCase)的上下文中,问题(至少表面上)是“cookies”对象是一个哈希表,而当您与控制器一起工作时,它是一个ActionDispatch::Cookies::CookieJar对象。因此,我们需要将其转换为CookieJar对象,以便我们可以在其上使用“signed”方法将其转换为SignedCookieJar。
您可以将以下内容放入功能测试中(在获取请求之后),以将cookie从哈希表转换为CookieJar对象:
@request.cookies.merge!(cookies)
cookies = ActionDispatch::Cookies::CookieJar.build(@request)

我有完全相同的问题。我正在使用测试单元。我不明白如何使用你的两行代码。我尝试了不同的排列组合,但都没有起作用。你能否请给出一个更详细的例子来说明如何使用它。 - allesklar

0

问题似乎也出现在您的测试中。

这是一些代码和测试,我用来TDD解决方案,其中您想要从将params值传递到视图中设置cookie的值。

功能测试:

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行中的cookies是一个字符串...这也是导致此测试未通过的原因之一,是在cookies[:reference]中放置了一个符号,测试不喜欢那样做,所以我没有这样做。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接