【问题标题】:RSpec: Stub controller method in request specRSpec:请求规范中的存根控制器方法
【发布时间】:2020-03-19 06:39:19
【问题描述】:

我正在写一个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 方法。

测试当前通过并且控制器按预期工作。我的问题是关于这条线的:

allow_any_instance_of(ItemsController).to receive(:current_user).and_return(user)

我根据How to stub ApplicationController method in request spec 中的答案写了这行代码,它有效。但是,the RSpec docs call it a "code smell"rubocop-rspec 抱怨“RSpec/AnyInstance: Avoid stubbing using allow_any_instance_of”。

另一种方法是获取对控制器的引用并使用instance_double(),但我不确定如何从请求规范中获取对控制器的引用。

我应该如何编写此测试以避免代码异味/遗留测试方法?

【问题讨论】:

    标签: ruby-on-rails rspec doorkeeper


    【解决方案1】:

    你应该在度假。

    我认为正确的方法是在请求规范中尽可能避免存根,门卫需要一个令牌来授权,所以我会这样做:

    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 点!

    【讨论】:

    • ? 这让我更接近了,谢谢!不过,我仍然无法生成有效的访问令牌。我将发布一个单独的问题。
    • 如果您有兴趣,这是我的后续问题:stackoverflow.com/q/60764500/1445366
    【解决方案2】:

    你想过不要嘲笑current_user吗?

    如果您在请求规范之前编写了一个测试助手来登录user,则current_user 将像真实用户一样自动填充。代码如下所示:

    before do
      sign_in user
      get '/items'
      @parsed_body = JSON.parse(response.body)
    end
    

    如果您使用devise gem 进行身份验证,它有一个关于here 的很好的书面维基页面。

    @dhh here 也推荐这种方法

    【讨论】:

    • 谢谢,您提供的链接真的很有帮助。看起来sign_in 在我的情况下不起作用,因为我使用的是带有访问令牌的门卫。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多