我正试图在我的RSpec测试中找到创建用户令牌的最佳方法,并尽可能雄辩地编写它们。
以下是我的项目类的一个示例。从下面的规范中,您将看到我正在使用DoorKeeper来保持API端点在除show之外的所有操作上的安全性。
我遇到的问题是如何最好地创建@access_token
。
这是有效的,通过了所有的例子,但我担心我不遵守DRY原则。如果有很多动作/上下文需要@access_token
,那么有什么方法可以将它抽象出来给某个帮助者?
提前致谢
## projects_spec.rb
require 'spec_helper'
describe "Projects API" do
describe "#index" do
FactoryGirl.create(:project)
context 'with a valid token' do
before(:each) do
user = FactoryGirl.create(:user)
authentication = FactoryGirl.create(:authentication, user: user)
application = Doorkeeper::Application.create!(:name => "MyApp", :redirect_uri => "http://app.com")
@access_token = Doorkeeper::AccessToken.create!(:application_id => application.id, :resource_owner_id => authentication.identity.id)
end
it 'returns a list of projects' do
get '/api/v1/projects', access_token: @access_token.token
expect(response.status).to eq(200)
# check the JSON is as we expect
end
end
context 'without a token' do
it 'responds with 401' do
get '/api/v1/projects'
expect(response.status).to eq(401)
end
end
end
describe "#create" do
context 'with a valid token' do
before(:each) do
user = FactoryGirl.create(:user)
authentication = FactoryGirl.create(:authentication, user: user)
application = Doorkeeper::Application.create!(:name => "MyApp", :redirect_uri => "http://app.com")
@access_token = Doorkeeper::AccessToken.create!(:application_id => application.id, :resource_owner_id => authentication.identity.id)
end
context 'with required params' do
project_params = {
name: "Win the lottery",
strapline: "The best feeling in the world"
}
it "creates a project and responds with 201" do
post "/api/v1/projects", :project => project_params, access_token: @access_token.token
expect(response.status).to eq(201)
# check the JSON is as we expect
end
end
context 'without required params' do
project_params = {
strapline: "Stepney City Farm's pallets, woodchips and compost",
}
it "responds with 422 and no record created" do
post "/api/v1/projects", :project => project_params, access_token: @access_token.token
expect(response.status).to eq(422)
json = JSON.parse(response.body)
expect(json['project']['errors'].length).to eq(1)
end
end
end
context 'without a token' do
it 'responds with 401' do
get '/api/v1/projects'
expect(response.status).to eq(401)
end
end
end
describe "#show" do
it 'returns a projects' do
project = FactoryGirl.create(:project, name: "A new project")
get "/api/v1/projects/#{project.id}"
expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json['project']['name']).to eq(project.name)
expect(GroupRun.last.name).to eq(project.name)
# check the JSON is as we expect
end
end
end
答案 0 :(得分:1)
我有一些技巧可以用来处理这些东西。
第一种是在let
上使用普通红宝石方法。这只是我的偏好,我认为它增加了测试的清晰度。请查看此内容以获取更多相关信息:http://robots.thoughtbot.com/lets-not
然后,我有一个auth东西的辅助方法。我正在使用Devise进行身份验证,因此我的实现将与您的实现不同,但是在测试中调用helper方法后,这会为我的应用程序的每个请求设置HTTP_AUTHORIZATION标头。
module Requests
module AuthenticationHelpers
def basic_http_auth(user)
credentials = ActionController::HttpAuthentication::Basic.encode_credentials(user.email,user.password)
Rack::MockRequest::DEFAULT_ENV['HTTP_AUTHORIZATION'] = credentials
end
end
end
然后在实际测试中,我会做这样的事情:
describe "GET /api/v1/messages" do
it 'returns an array of messages' do
get '/api/v1/messages'
basic_http_auth(FactoryGirl.create(:user))
expect(response).to eq(200)
end
end
因此,如果您要在许多API测试中使用它,请将其移至支持帮助程序中。并且,如果您在同一个文件中多次调用某些内容,请编写一个方法(或将其置于let
调用中)以干燥您的测试。
答案 1 :(得分:1)
根据Matthew的答案,使用门卫,我最终使用了以下内容:
module TokenMacros
def generate_access_token_for(user = nil)
user ||= FactoryGirl.create(:user)
authentication = FactoryGirl.create(:authentication, user: user)
application = Doorkeeper::Application.create!(:name => "MyApp", :redirect_uri => "http://app.com")
access_token = Doorkeeper::AccessToken.create!(:application_id => application.id, :resource_owner_id => authentication.identity.id)
access_token.token
end
end
然后允许我打电话给...
let(:user) { FactoryGirl.create(:user) }
let(:token) { generate_access_token_for(user) }
灿烂
答案 2 :(得分:0)
避免重复的最简单方法是在最高级别描述中定义令牌,以便它可用于规范中的所有示例。
此外,为了避免不依赖于它的示例出现任何性能问题,您可以使用let
而非before
来定义令牌,因为let
已被延迟评估
您拥有的是以下内容:
let(:access_token) do
user = FactoryGirl.create(:user)
authentication = FactoryGirl.create(:authentication, user: user)
application = Doorkeeper::Application.create!(:name => "MyApp", :redirect_uri => "http://app.com")
Doorkeeper::AccessToken.create!(:application_id => application.id, :resource_owner_id => authentication.identity.id)
end
您还需要将对此令牌的引用从@access_token
更改为access_token
,因为您要定义方法而不是实例变量。