Buz*_*uzz 16 authorization rspec ruby-on-rails request
我正在使用rspec请求来测试需要在每个请求的标头中使用api-key的JSON API.
我知道我可以这样做:
get "/v1/users/janedoe.json", {}, { 'HTTP_AUTHORIZATION'=>"Token token=\"mytoken\"" }
Run Code Online (Sandbox Code Playgroud)
但是,对每个请求执行此操作都很繁琐.
我已经尝试request.env
在前面的块中设置,但是我得到了no method NilClass error
自从请求不存在.
我需要一些方法,也许在这里spec-helper
,全局获取与所有请求一起发送的标头.
cad*_*lac 10
要在before hook中设置它,你需要像访问它一样
config.before(:each) do
controller.request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials('mytoken')
end
Run Code Online (Sandbox Code Playgroud)
我也讨厌巨型哈希,但更喜欢在不同的步骤中明确授权用户.毕竟,这是一个相当关键的部分,而且.所以我的解决方案是:
#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
Run Code Online (Sandbox Code Playgroud)
然后我可以这样使用它
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
Run Code Online (Sandbox Code Playgroud)
我觉得这非常适合测试不同的授权级别.或者,你可以让helper方法指定authorize函数并得到相同的结果,就像这样
#spec/helpers/controller_spec_helpers.rb
module ControllerSpecHelpers
def authenticate
controller.stub(:authenticate! => true)
end
end
Run Code Online (Sandbox Code Playgroud)
但是,为了获得最佳速度和控制,您可以将它们组合起来
#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
Run Code Online (Sandbox Code Playgroud)
然后用.授权整个块
#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
...
Run Code Online (Sandbox Code Playgroud)
如果你正在做一个帖子,这是另一种方法.
@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)
Run Code Online (Sandbox Code Playgroud)
注意interaction_params只是我传入的json对象.
我知道这个问题已经回答,但这是我的看法。对我有用的东西:
request.headers['Authorization'] = token
Run Code Online (Sandbox Code Playgroud)
代替:
request.env['Authorization'] = token
Run Code Online (Sandbox Code Playgroud)
如果您不测试标头本身,我认为您不应该依赖标头,您应该存根检查 HTTP_AUTORIZATION 是否存在的方法,并使其对除测试特定标头的规范之外的所有规范返回 true
类似...在控制器上
Controller...
before_filter :require_http_autorization_token
methods....
protected
def require_http_autorization_token
something
end
Run Code Online (Sandbox Code Playgroud)
在规格上
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
Run Code Online (Sandbox Code Playgroud)
这样人们就可以忘记令牌并测试您真正想要测试的内容