RSpec:请求规范中的存根控制器方法
RSpec: Stub controller method in request spec
我正在写一个 RSpec request spec,它看起来大致像(为简洁起见略微缩短):
describe 'Items', type: :request do
describe 'GET /items' do
before do
allow_any_instance_of(ItemsController).to receive(:current_user).and_return(user)
get '/items'
@parsed_body = JSON.parse(response.body)
end
it 'includes all of the items' do
expect(@parsed_body).to include(item_1)
expect(@parsed_body).to include(item_2)
end
end
end
控制器看起来像:
class ItemsController < ApplicationController
before_action :doorkeeper_authorize!
def index
render(json: current_user.items)
end
end
如您所见,我正在尝试对门卫的 current_user
方法进行 stub。
目前测试通过,控制器按预期工作。我的问题是关于这条线的:
allow_any_instance_of(ItemsController).to receive(:current_user).and_return(user)
我根据 How to stub ApplicationController method in request spec, and it works. However, the RSpec docs call it a "code smell" 中的答案写了这一行,rubocop-rspec
抱怨说,“RSpec/AnyInstance: Avoid stubbing using allow_any_instance_of
”。
一种替代方法是获取对控制器的引用并使用 instance_double()
,但我不确定如何从请求规范中获取对控制器的引用。
我应该如何编写此测试以避免代码异味/遗留测试方法?
你有没有想过不要嘲笑 current_user
?
如果您编写测试助手在您的请求规范之前登录 user
,current_user
将自动填充,就好像它是真实用户一样。代码如下所示:
before do
sign_in user
get '/items'
@parsed_body = JSON.parse(response.body)
end
如果您使用 devise
gem 进行身份验证,它有一个很好的书面维基页面关于 here。
@dhh
也推荐 here 这种方法
你应该去度假了。
我认为正确的方法是尽可能避免在请求规范中存根,看门人需要一个令牌来授权所以我会做类似的事情:
describe 'Items', type: :request do
describe 'GET /items' do
let(:application) { FactoryBot.create :oauth_application }
let(:user) { FactoryBot.create :user }
let(:token) { FactoryBot.create :access_token, application: application, resource_owner_id: user.id }
before do
get '/items', access_token: token.token
@parsed_body = JSON.parse(response.body)
end
it 'includes all of the items' do
expect(@parsed_body).to include(item_1)
expect(@parsed_body).to include(item_2)
end
end
end
以下是 some examples 这些工厂的样子。
最后,好SO点!
我正在写一个 RSpec request spec,它看起来大致像(为简洁起见略微缩短):
describe 'Items', type: :request do
describe 'GET /items' do
before do
allow_any_instance_of(ItemsController).to receive(:current_user).and_return(user)
get '/items'
@parsed_body = JSON.parse(response.body)
end
it 'includes all of the items' do
expect(@parsed_body).to include(item_1)
expect(@parsed_body).to include(item_2)
end
end
end
控制器看起来像:
class ItemsController < ApplicationController
before_action :doorkeeper_authorize!
def index
render(json: current_user.items)
end
end
如您所见,我正在尝试对门卫的 current_user
方法进行 stub。
目前测试通过,控制器按预期工作。我的问题是关于这条线的:
allow_any_instance_of(ItemsController).to receive(:current_user).and_return(user)
我根据 How to stub ApplicationController method in request spec, and it works. However, the RSpec docs call it a "code smell" 中的答案写了这一行,rubocop-rspec
抱怨说,“RSpec/AnyInstance: Avoid stubbing using allow_any_instance_of
”。
一种替代方法是获取对控制器的引用并使用 instance_double()
,但我不确定如何从请求规范中获取对控制器的引用。
我应该如何编写此测试以避免代码异味/遗留测试方法?
你有没有想过不要嘲笑 current_user
?
如果您编写测试助手在您的请求规范之前登录 user
,current_user
将自动填充,就好像它是真实用户一样。代码如下所示:
before do
sign_in user
get '/items'
@parsed_body = JSON.parse(response.body)
end
如果您使用 devise
gem 进行身份验证,它有一个很好的书面维基页面关于 here。
@dhh
也推荐 here 这种方法你应该去度假了。
我认为正确的方法是尽可能避免在请求规范中存根,看门人需要一个令牌来授权所以我会做类似的事情:
describe 'Items', type: :request do
describe 'GET /items' do
let(:application) { FactoryBot.create :oauth_application }
let(:user) { FactoryBot.create :user }
let(:token) { FactoryBot.create :access_token, application: application, resource_owner_id: user.id }
before do
get '/items', access_token: token.token
@parsed_body = JSON.parse(response.body)
end
it 'includes all of the items' do
expect(@parsed_body).to include(item_1)
expect(@parsed_body).to include(item_2)
end
end
end
以下是 some examples 这些工厂的样子。
最后,好SO点!