8

是否可以通过单元测试覆盖我的控制器,这高度依赖于 Etags?

这就是我想要做的:如果页面不是陈旧的(意味着它是新鲜的),我将添加一些标题来响应。

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

但是,它在浏览器中完美运行。我已经尝试过声明 ActionController::Base.perform_caching = true,它不会改变整体情况。

谢谢

4

6 回答 6

11

以下是测试第二个请求是否返回 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
于 2013-03-11T21:09:13.707 回答
5

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
于 2011-09-08T05:37:18.973 回答
4

好的,这里有一点:

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

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

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

于 2010-04-15T10:54:54.610 回答
1

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

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

于 2013-05-28T01:24:19.027 回答
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'
)
于 2015-02-19T20:08:14.773 回答
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

于 2019-04-24T23:04:13.297 回答