如何测试rails ETag缓存?

时间:2010-04-15 10:12:14

标签: ruby-on-rails rspec etag

是否有可能覆盖我的控制器,这与Etags的单元测试非常相关?

这是我正在尝试做的事情: 如果页面不是陈旧的(意味着它是新鲜的),我正在为响应添加一些标题。

当我尝试全部测试(rspec)时,无论我有多少类似的请求,我仍然会收到200 OK而不是304,并且我的标题不会被修改。此外,如果我跟踪request.fresh?(响应),它总是错误的。

然而,它完全适用于浏览器。 我已经尝试说过ActionController :: Base.perform_caching = true,它不会改变整体情况。

谢谢

6 个答案:

答案 0 :(得分:9)

以下是测试第二个请求是否返回304响应的方法:

    get action, params
    assert_response 200, @response.body
    etag = @response.headers["ETag"]
    @request.env["HTTP_IF_NONE_MATCH"] = etag
    get action, params
    assert_response 304, @response.body

答案 1 :(得分:4)

好的,这是重点:

在点击请求之前,请阅读与Rails代码中的ETag相关的所有内容 并且不要忘记设置:

request.env["HTTP_IF_MODIFIED_SINCE"]
request.env["HTTP_IF_NONE_MATCH"]

因为它们是ETag测试所必需的。

答案 2 :(得分:4)

Rails哈希:你提供的etag:

headers['ETag'] = %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")

所以设置简单的

frash_when(:etag => 'foo')

只会由正确的摘要触发(双引号是必要的)

def with_etag
  if stale?(:etag => 'foo')
    render :text => 'OK'
  end
end

... tested by ...

@request.env['HTTP_IF_NONE_MATCH'] = '"acbd18db4cc2f85cedef654fccc4a4d8"'
get :with_etag
assert_equal 304, @response.status.to_i

同样适用于修改:

def with_modified
  if stale?(:last_modified => 1.minute.ago)
    render :text => 'OK'
  end
end

... tested by ...

@request.env['HTTP_IF_MODIFIED_SINCE'] = 2.minutes.ago.rfc2822
get :with_modified
assert_equal 304, @response.status.to_i

答案 3 :(得分:1)

这个要点在rspec中非常有用的重新标签测试 -

https://gist.github.com/brettfishman/3868277

答案 4 :(得分:0)

Rails 4.2现在也考虑了模板的摘要。对我来说,以下工作:

def calculate_etag(record, template)
  Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key([
    record,
    controller.send(:lookup_and_digest_template, template)
  ])).inspect
end

def set_cache_headers(modified_since: nil, record: nil, template: nil)
  request.if_modified_since = modified_since.rfc2822
  request.if_none_match = calculate_etag(record, template)
end

set_cache_headers(
  modified_since: 2.days.ago,
  record: @book,
  template: 'books/index'
)

答案 5 :(得分:0)

至少在Rails 5.2中,szeryf的解决方案失败。此变体确实有效:

get action, parms
assert_response 200, @response.code
etag = @response.headers["ETag"]
get action, parms, headers: { "HTTP_IF_NONE_MATCH": etag }
assert_response 304, @response.code

请参见Rails指南:https://guides.rubyonrails.org/testing.html#setting-headers-and-cgi-variables