无法使用 rspec 存根辅助方法

Posted

技术标签:

【中文标题】无法使用 rspec 存根辅助方法【英文标题】:Unable to stub helper method with rspec 【发布时间】:2012-05-19 06:11:01 【问题描述】:

我正在尝试在我的控制器中定义的帮助程序上存根方法。例如:

class ApplicationController < ActionController::Base
  def current_user
    @current_user ||= authenticated_user_method
  end
  helper_method :current_user
end

module SomeHelper
  def do_something
    current_user.call_a_method
  end
end

在我的 Rspec 中:

describe SomeHelper
  it "why cant i stub a helper method?!" do
    helper.stub!(:current_user).and_return(@user)
    helper.respond_to?(:current_user).should be_true # Fails
    helper.do_something # Fails 'no method current_user'
  end
end

spec/support/authentication.rb

module RspecAuthentication
  def sign_in(user)
    controller.stub!(:current_user).and_return(user)
    controller.stub!(:authenticate!).and_return(true)

    helper.stub(:current_user).and_return(user) if respond_to?(:helper)
  end
end

RSpec.configure do |config|
  config.include RspecAuthentication, :type => :controller
  config.include RspecAuthentication, :type => :view
  config.include RspecAuthentication, :type => :helper
end

我问了一个类似的问题here,但解决了一个问题。这种奇怪的行为再次蔓延,我想了解为什么这不起作用。

更新:我发现在helper.stub!(...) 之前调用controller.stub!(:current_user).and_return(@user) 是导致这种行为的原因。这很容易在spec/support/authentication.rb 中修复,但这是 Rspec 中的错误吗?我不明白为什么如果它已经在控制器上存根,为什么不能在助手上存根方法。

【问题讨论】:

尝试通过 ApplicationController 对方法进行存根,因为这是定义它的地方。 ApplicationController.stub(:current_user =&gt; @user) 编辑:现在我想这可能行不通。 不,它没有用。我也试过any_instance,但没有运气。我实际上已经让它工作了,但我有点困惑(可能发现了 rspec 的错误)。我会尽快更新问题。 听起来像一个错误。绝对值得在github.com/rspec/rspec-mocks/issues 提交问题(并尝试使用最新版本)。 创建票证:github.com/rspec/rspec-mocks/issues/135 我也有同样的问题,请问有解决办法吗? 【参考方案1】:

更新 Matthew Ratzloff 的回答:您不需要实例对象和存根!已弃用

it "why can't I stub a helper method?!" do
  helper.stub(:current_user)  user 
  expect(helper.do_something).to eq 'something'
end

编辑。 stub! 的 RSpec 3 方式是:

allow(helper).to receive(:current_user) user

见:https://relishapp.com/rspec/rspec-mocks/v/3-2/docs/

【讨论】:

我修正了 RSpec 3 的答案。【参考方案2】:

在 RSpec 3.5 RSpec 中,似乎无法再从 it 块访问 helper。 (它会给你以下信息:

helper 在示例中(例如 it 块)或在示例范围内运行的构造(例如 beforelet 等)中不可用。它仅适用于示例组(例如 describecontext 块)。

(我似乎找不到任何有关此更改的文档,这都是通过实验获得的知识)。

解决这个问题的关键是知道辅助方法是实例方法,并且对于您自己的辅助方法,这样做很容易:

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

这就是最终对我有用的方法

脚注/贷记到期:

Super Props to a blog entry by Johnny Ji about their struggles stubbing helper/instance methods

【讨论】:

【参考方案3】:

试试这个,它对我有用:

describe SomeHelper
  before :each do
    @helper = Object.new.extend SomeHelper
  end

  it "why cant i stub a helper method?!" do
    @helper.stub!(:current_user).and_return(@user)
    # ...
  end
end

第一部分基于RSpec作者this reply,第二部分基于this Stack Overflow answer。

【讨论】:

... 然后测试实际上需要测试@helper,而不是 SomeHelper。【参考方案4】:

Rspec 3

  user = double(image: urlurl)
  allow(helper).to receive(:current_user).and_return(user)
  expect(helper.get_user_header).to eq("/uploads/user/1/logo.png")

【讨论】:

【参考方案5】:

这在 RSpec 3 的情况下对我有用:

let(:user)  create :user 
helper do
  def current_user; end
end
before do
  allow(helper).to receive(:current_user).and_return user
end

【讨论】:

非常聪明。首先,您在助手中定义缺少的方法(来自另一个助手,控制器),然后将其存根。 def ... 块可以直接使用user,所以不需要存根吗?【参考方案6】:

从 RSpec 3.10 开始,此技术将起作用:

  before do
    without_partial_double_verification  
      allow(view).to receive(:current_user).and_return(user)
    
  end

需要without_partial_double_verification 包装器来避免MockExpectationError,除非您已全局关闭它。

【讨论】:

以上是关于无法使用 rspec 存根辅助方法的主要内容,如果未能解决你的问题,请参考以下文章

rspec 3 - 存根类方法

如何在RSpec中存根?

使用Rspec存根和模拟在Rails Oauth中实现100%的测试覆盖率

有没有办法用 Rspec 存根包含模块的方法?

RSpec 存根方法可以按顺序返回不同的值吗?

Rspec 模拟和存根与期望混淆