Ruby on rails RSpec请求-如何为所有请求设置http授权标头

Ruby on rails RSpec请求-如何为所有请求设置http授权标头,ruby-on-rails,rspec,request,authorization,Ruby On Rails,Rspec,Request,Authorization,我使用rspec请求测试一个JSON API,该API需要在每个请求的头中有一个API键 我知道我能做到: get "/v1/users/janedoe.json", {}, { 'HTTP_AUTHORIZATION'=>"Token token=\"mytoken\"" } 但对每个请求都这样做是很乏味的 我尝试在before块中设置request.env,但由于请求不存在,因此得到了no-method-NilClass错误 我需要某种方法,可能是在规范帮助程序中,全局地将此头与所有

我使用rspec请求测试一个JSON API,该API需要在每个请求的头中有一个API键

我知道我能做到:

get "/v1/users/janedoe.json", {}, { 'HTTP_AUTHORIZATION'=>"Token token=\"mytoken\"" }
但对每个请求都这样做是很乏味的

我尝试在before块中设置
request.env
,但由于请求不存在,因此得到了
no-method-NilClass错误


我需要某种方法,可能是在
规范帮助程序中
,全局地将此头与所有请求一起发送

我认为如果不测试报头本身,就不应该依赖报头,应该对检查HTTP_自动化是否存在的方法进行存根,并使其对所有规范(测试该特定报头的规范除外)返回true

类似于。。。 在控制器上

Controller...
  before_filter :require_http_autorization_token

  methods....

  protected
  def require_http_autorization_token
    something
  end
按规格

before(:each) do
  controller.stub!(:require_http_autorization_token => true)
end

describe 'GET user' do
  it 'returns something' do
    #call the action without the auth token
  end

  it 'requires an http_autorization_token' do
    controller.unstub(:require_http_autorization_token)
    #test that the actions require that token
  end
end

这样一来,你就可以忘记令牌,测试你真正想测试的东西了。如果你在写帖子,这是另一种方法

@authentication_params = { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Token.encode_credentials(Temp::Application.config.api_key) }

expect { post "/api/interactions", @interaction_params, @authentication_params }.to change(Interaction, :count).by(1)

注意:interaction_params只是我传入的一个json对象。

要在before钩子中设置它,您需要像

config.before(:each) do
  controller.request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials('mytoken')
end
我也讨厌庞大的散列,但更喜欢在不同的步骤中明确授权用户。毕竟,这是一个相当关键的部分,而且。所以我的解决方案是:

#spec/helpers/controller_spec_helpers.rb
module ControllerSpecHelpers
  def authenticate user
    token = Token.where(user_id: user.id).first || Factory.create(:token, user_id: user.id)
    request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials(token.hex)
  end
end

#spec/spec_helper.rb
RSpec.configure do |config|
  ...
  config.include ControllerSpecHelpers, :type => :controller
那我就可以这样用了

describe Api::V1::Users, type: :controller do
  it 'retrieves the user' do
    user = create :user, name: "Jane Doe"
    authorize user
    get '/v1/users/janedoe.json'
  end
end
我发现这非常适合测试不同的授权级别。或者,您可以让helper方法指定authorize函数并获得相同的结果,如下所示

#spec/helpers/controller_spec_helpers.rb
module ControllerSpecHelpers
  def authenticate
    controller.stub(:authenticate! => true)
  end
end
但是,为了获得最高的速度和控制,您可以将它们结合起来

#spec/helpers/controller_spec_helpers.rb
module ControllerSpecHelpers
  def authenticate user = nil
    if user
      token = Token.where(user_id: user.id).first || Factory.create(:token, user_id: user.id)
      request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials(token.hex)
    else
      controller.stub(:authenticate! => true)
    end
  end
end
然后用

#spec/spec_helper.rb
...
RSpec.configure do |config|
  ...
  config.before(:each, auth: :skip) { authenticate }

#**/*_spec.rb
describe Api::V1::Users, type: :controller do
  context 'authorized', auth: :skip do
    ...

我知道这个问题已经得到了回答,但我的看法是这样的。一些对我有用的东西:

request.headers['Authorization'] = token
而不是:

request.env['Authorization'] = token

您的代码是否缺少一些括号
authenticate user=nil
,并且您含糊不清地使用了
authenticate
authorize