RSpec:如何存根继承的方法 current_user (无需 Devise)?

问题描述 投票:0回答:5

我有一个基于 MHartl 的 RoR4 教程

的控制器

就像 MHartl 一样,我没有使用 Devise,我推出了自己的身份验证系统

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)>'

用户控制器:

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

我发现这篇非常有帮助的文章给了我希望,我走在正确的轨道上,但我无法让它发挥作用。

据我所知(更新):

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(路径)。在 RSpec 和 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
5个回答
40
投票

如果您正在对控制器进行单元测试,您可以简单地将

current_user
存根在之前的块中,如下所示:

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

这将避免在您的功能环境中生成多个会话,也避免多次登录


10
投票

也有效

user = create(:user) #FactoryBot

allow(controller).to receive(:current_user).and_return(user)

1
投票

对我来说,合作过:

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

1
投票

我在旧版 Rails 4 应用程序中遇到了同样的问题,并且我的解决方案基于 Rspec Views 的 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
非常重要,因为块内的内容将在测试范围之外延迟执行,否则用户将为零


0
投票

为什么不嘲笑

can?
方法?

我遇到了同样的问题,因为如果

can?
失败,它会显示错误未定义的方法:
current_user

修复了它

allow(view).to receive(:can?).with(:show, customer).and_return(true)
© www.soinside.com 2019 - 2024. All rights reserved.