【问题标题】:RSpec: how to stub inherited method current_user (w/o Devise)?RSpec:如何存根继承的方法 current_user(没有设计)?
【发布时间】:2014-08-22 17:21:47
【问题描述】:

我有一个基于 MHartl 的 RoR4 Tutorial 的控制器

和 MHartl 一样,我没有使用 Devise,我rolled my own authentication system

UsersController#Edit 的 RSpec 出现问题,因为视图调用了current_user.admin?,而控制器调用了@path_switch = path_switch

我不断收到 RSpec 错误:

1) User Pages Edit 
 Failure/Error: visit edit_user_path(user)
 NoMethodError:
   undefined method `admin?' for nil:NilClass
 # ./app/controllers/users_controller.rb:106:in `path_switch'
 # ./app/controllers/users_controller.rb:53:in `edit'
 # ./spec/requests/user_pages_spec.rb:54:in `block (3 levels) in <top (required)>'

UsersController:

class UsersController < ApplicationController
  ...
  def edit
    @user = User.find(params[:id])
    @path_switch ||= path_switch                        #error
  end
  ...
  def path_switch
    if current_user.admin?                               #error
      users_path
    else
      root_path
    end
  end
end

我发现这个really helpful article 让我希望我走在正确的轨道上,但我无法让它发挥作用。

据我所知(更新):

user_pages_spec.rb:

require 'spec_helper'
require 'support/utilities'

describe "User Pages" do
  #include SessionsHelper

  let(:user) { FactoryGirl.create(:user) }
  let(:current_user) {user}

  subject { page }

  describe "Edit" do
    before do
      sign_in(user)
      visit edit_user_path(user) 
    end

    it '(check links and content)' do
      should have_button('Submit')
      should have_link('Cancel')
      should have_content(user.fname+"\'s profile")
    end
   ...
  end
...
end

但是current_user 还是会回来nil

感谢任何帮助/指导。谢谢!


include SessionsHelper 添加到我的user_pages_edit.rb 的顶部描述块似乎尝试使用该助手的sign_in(path)。创建一个issue between RSpec and cookies.permanent。所以这是一个半身像。

不幸的是,这让我回到了我的 .admin? 错误。

current_user.admin? 有两个电话

控制器中有一个:

  def path_switch
    if current_user.admin?    #error current_user == nil
      users_path
    else
      root_path
    end
  end

一个被认为是 ERB:

<% if current_user.admin? %>
  <div class="row  col-xs-6 col-sm-6 col-md-3">
    <div class="input-group input-selector">
    ...

我需要做的就是弄清楚如何设置current_user.admin = true 并将其传递给控制器​​(然后希望是视图),以便可以加载页面。 为此,我需要做的就是设置current_user = user,因为user.admin == true

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 rspec stub


    【解决方案1】:

    如果您正在对控制器进行单元测试,您可以简单地将 current_user 存根在 before 块中,如下所示:

    let(:user) { ... }
    
    # RSpec version <= 2 syntax:
    before { controller.stub(:current_user) { user } }
    
    # RSpec version >= 3 syntax:
    before { allow(controller).to receive(:current_user) { user } }
    

    如果您正在执行功能或请求测试,我建议您通过在数据库中创建一个用户来执行真正的登录,然后使用此用户凭据通过您的登录页面


    这里你好像在做一个功能测试,你应该写一个助手来执行用户记录的创建并通过登录。

    此外,在功能测试中,为了在运行测试时获得大量时间,请不要犹豫,将您的断言分组到同一个块中。显然,而不是:

    it { should have_button('Submit')}
    it { should have_link('Cancel')}
    it { should have_content(user.fname+"\'s profile")}
    

    你可以写

    it 'check links and content' do
      should have_button('Submit')
      should have_link('Cancel')
      should have_content(user.fname+"\'s profile")
    end
    

    这样可以避免生成多次你的功能环境的会话,也避免多次登录

    【讨论】:

    • 我通过单元测试和功能测试策略的尝试更新了我的问题。感谢您的阻止建议!
    • 如果你得到undefined method allow' for RSpec`意味着你使用的是旧版本的rspec,所以stub语法将被使用
    • 那么allow(controller).to receive(:current_user) { user } 会变成controller.stub(:current_user) { user } 吗?我正在努力为此寻找 api 文档。我确实找到了这个:stub_const(constant_name, value, options = {})
    • 我同意您的评论,即这是一项功能测试,并且非常希望该方法能够正常工作。知道为什么我的文件都没有调用 .empty? 但 RSpec 错误说这是问题所在?它是否在某个地方的核心出错?如何找出 nil 对象正在获取 .empty? 调用?
    • relishapp.com/rspec rspec doc,一定要选择正确的版本,至于查找错误消息的来源,如果您无法通过阅读回溯找到它,则必须使用调试器跨度>
    【解决方案2】:

    同样有效

    user = create(:user) #FactoryBot
    
    allow(controller).to receive(:current_user).and_return(user)
    

    【讨论】:

    • 这仍然适用于 Rspec 3.7 和 Rails 5.1。我只是在这里检查
    • 这是最简单的方法。除非绝对需要,否则不要使用 Devise 助手。只是头疼。
    • 注意,如果你在 Helper 规范中,你需要使用 allow(helper) 而不是 allow(controller)。否则,相同并且效果很好。谢谢。
    【解决方案3】:

    对我来说,曾与:

    before { controller.stub!(:current_user).and_return(user) }
    

    【讨论】:

      【解决方案4】:

      我在旧版 Rails 4 应用程序中遇到了同样的问题,我的解决方案基于 Rspec 视图的 this 测试用例。

      首先定义一个助手,它将在控制器实例中定义缺少的助手方法

      # /spec/support/concerns/view_helper.rb
      module ViewHelper
        def include_current_user_helper(&block)
          controller.singleton_class.class_eval do
            define_method :current_user, &block
            helper_method :current_user
          end
        end
      end
      

      然后配置 Rspec 以将其包含在所有视图助手中

      # spec/rails_helper.rb
      # ...
      Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
      
      RSpec.configure do |config|
        # ...
        config.include ViewHelper, type: :view
      end
      

      在视图规范中它是这样调用的

      RSpec.describe 'something' do
        let!(:user) { FactoryGirl.create(:user) } # Note the "!" there
        before { include_current_user_helper { user } }
      
        # do stuff
      end
      

      注意:使用 bang 调用 let 很重要,因为块内的内容将在测试范围之外延迟执行,否则用户将为零

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多