19

我正在使用 rspec 请求来测试一个 JSON API,该 API 在每个请求的标头中都需要一个 api-key。

我知道我可以这样做:

get "/v1/users/janedoe.json", {}, { 'HTTP_AUTHORIZATION'=>"Token token=\"mytoken\"" }

但是对每个请求都这样做很乏味。

我已经尝试request.env在 before 块中进行设置,但我得到了no method NilClass error因为请求不存在。

我需要某种方式,也许在spec-helper, 来全局获取这个标头与所有请求一起发送。

4

4 回答 4

13

要将其设置在 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

我发现这非常适合测试不同的授权级别。或者,您可以让辅助方法指定授权函数并获得相同的结果,如下所示

#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
    ...
于 2014-06-08T21:27:41.817 回答
10

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

request.headers['Authorization'] = token

代替:

request.env['Authorization'] = token
于 2017-11-07T11:48:45.260 回答
6

如果您正在发帖,这是另一种方法。

@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 对象。

于 2014-02-26T07:28:24.987 回答
1

如果您不测试标头本身,我认为您不应该依赖标头,您应该存根检查 HTTP_AUTORIZATION 是否存在的方法,并使其对除测试特定标头的规范之外的所有规范返回 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

这样人们就可以忘记令牌并测试您真正想要测试的内容

于 2012-10-06T22:59:38.457 回答