【问题标题】:Rspec: add some header requests inside routing specsRspec:在路由规范中添加一些标头请求
【发布时间】:2012-07-11 16:14:46
【问题描述】:

我正在开发一个 Rails 应用程序,该应用程序具有 JSON 格式的 REST API 和版本(根据 Ryan 的优秀演员:http://railscasts.com/episodes/350-rest-api-versioning)。

例如,有一个规范/请求规范:

require 'spec_helper'

describe "My Friends" do
  describe "GET /my/friends.json" do
    it "should get my_friends_path" do
      get v1_my_friends_path, {}, {'HTTP_ACCEPT' => 'application/vnd.myapp+json; level=1'}
      response.status.should be(401)
    end
  end
end

而且效果很好。但是(保持这个例子)我们如何编写路由规范?例如这个规范是不正确的:

require 'spec_helper'

describe "friends routing" do
  it "routes to #index" do
    get("/my/friends.json", nil, {'HTTP_ACCEPT' => 'application/vnd.myapp+json; level=1'}).
      should route_to({ action: "index",
                    controller: "api/v1/private/my/friends",
                        format: "json" })
  end
end

我尝试了不同的方式(例如request.headers['Accept']@request.headers['Accept'],其中request 未定义,@request 为零);我真的不知道该怎么做。

我使用的是 Ruby 1.9.3、Rails 3.2.6 和 rspec-rails 2.11.0。谢谢。

【问题讨论】:

    标签: ruby-on-rails rspec rspec-rails


    【解决方案1】:

    通过结合 Cristophe 和 Piotr 的回答中的想法,我想出了一个适合我的解决方案。我正在使用 rspec 和 rails 3.0。

    it 'should route like i want it to' do 
      Rack::MockRequest::DEFAULT_ENV["HTTP_ACCEPT"] = "*/*"
      {get: "/foo/bar"}.
        should route_to(
        controller: 'foo',
        action: 'bar',
      )
      Rack::MockRequest::DEFAULT_ENV.delete "HTTP_ACCEPT"
    end
    

    【讨论】:

    • 您是如何克服“无法修改冻结的哈希”错误的?
    • @ChrisHough 嗯,我不记得有那个错误。但请注意,此解决方案适用于 rails 3。您可能使用的是 4.x,从那时起他们可能已经开始冻结 DEFAULT_ENV 哈希...
    • 是的,我不得不放弃我的路由规范来获取请求规范。这对我来说完全没问题。
    【解决方案2】:

    目前您无法在路由规范中发送额外的标头,这是因为 line 608actionpack-3.2.5/lib/action_dispatch/routing/route_set.rb 中写道:

    env = Rack::MockRequest.env_for(path, {:method => method})
    

    path 是您请求的路径"/my/friends.json",方法是:get 生成的 env 包含如下内容:

    {
     "rack.version"=>[1, 1],
     "rack.input"=>#<StringIO:0xb908f5c>,
     "rack.errors"=>#<StringIO:0xb908fac>,
     "rack.multithread"=>true,
     "rack.multiprocess"=>true,
     "rack.run_once"=>false,
     "REQUEST_METHOD"=>"GET",
     "SERVER_NAME"=>"your-url.com", # if path was http://your-url.com/
     "SERVER_PORT"=>"80",
     "QUERY_STRING"=>"",
     "PATH_INFO"=>"/",
     "rack.url_scheme"=>"http",
     "HTTPS"=>"off",
     "SCRIPT_NAME"=>"",
     "CONTENT_LENGTH"=>"0"
    }
    

    如果您能够模拟Rack::MockRequest::env_for,则应该可以注入除 env_for 生成的标头之外的其他标头(请参阅上面的哈希)。

    除了您当前使用的 route_to 匹配器错误之外,您应该在指定方法和路径的哈希上调用它,如下所示:

    { get: '/' }.should route_to(controller: 'main', action: 'index')
    

    如果您能够模拟出 env_for 并让它返回您的标头,请告诉我们,很高兴知道。

    问候 克里斯托夫

    【讨论】:

    • 您是如何克服“无法修改冻结的哈希”错误的?
    • 我可能使用的是旧版本的 rspec 或 ruby​​,其中哈希未冻结。
    【解决方案3】:
    before do
      ActionDispatch::TestRequest::DEFAULT_ENV["action_dispatch.request.accepts"] = "application/vnd.application-v1+json"
    end
    
    after do
      ActionDispatch::TestRequest::DEFAULT_ENV.delete("action_dispatch.request.accepts")
    end
    

    【讨论】:

    • 您是如何克服“无法修改冻结的哈希”错误的?
    【解决方案4】:

    您可以使用 rspec 的 and_wrap_original 来模拟 Rack::MockRequest.env_for 方法:

    expect(Rack::MockRequest).to receive(:env_for).and_wrap_original do |original_method, *args, &block|
      original_method.call(*args, &block).tap { |hash| hash['HTTP_ACCEPT'] = 'application/vnd.myapp+json; level=1' }
    end
    

    【讨论】:

    • @justNeph 您能否详细说明您是如何实现此功能的或您的规范是什么样的?
    • 您是如何克服“无法修改冻结的哈希”错误的?
    • @ChrisHough,您可以将其删除并返回新的哈希:
    • @ChrisHough hash = original_method.call(*args, &block).dup
    • 我会把这个放在哪里?在设计配置中?
    【解决方案5】:

    对于 Rails 3 和 4,我在 RSpec around hook 中完成了以下操作:

    around do |example|
      Rack::MockRequest::DEFAULT_ENV['HTTP_ACCEPT'] = 'application/vnd.vendor+json; version=1'
    
      example.run
    
      Rack::MockRequest::DEFAULT_ENV.delete 'HTTP_ACCEPT'
    end
    

    Rack &gt;= 2.0.3 (used by Rails 5) 到Rack::MockRequest::DEFAULT_ENV hash is frozen

    您可以重新定义常量并使用Kernel.silence_warnings 使 Ruby 警告静音:

    around do |example|
      silence_warnings do
        Rack::MockRequest::DEFAULT_ENV = Rack::MockRequest::DEFAULT_ENV.dup
      end
    
      Rack::MockRequest::DEFAULT_ENV['HTTP_ACCEPT'] = 'application/vnd.vendor+json; version=1'
    
      example.run
    
      Rack::MockRequest::DEFAULT_ENV.delete 'HTTP_ACCEPT'
    end
    

    这有点小技巧,但它就像一个魅力。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多