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

Posted

技术标签:

【中文标题】有没有办法用 Rspec 存根包含模块的方法?【英文标题】:Is there a way to stub a method of an included module with Rspec? 【发布时间】:2014-08-16 00:27:45 【问题描述】:

我有一个包含在另一个模块中的模块,它们都实现了相同的方法。 我想存根包含模块的方法,如下所示:

module M
  def foo
    :M
  end
end

module A
  class << self
    include M

    def foo
      super
    end
  end
end

describe "trying to stub the included method" do
  before  allow(M).to receive(:foo).and_return(:bar) 

  it "should be stubbed when calling M" do
    expect(M.foo).to eq :bar
  end

  it "should be stubbed when calling A" do
    expect(A.foo).to eq :bar
  end
end

第一个测试通过,但第二个输出:

Failure/Error: expect(A.foo).to eq :bar

   expected: :bar
        got: :M

为什么存根在这种情况下不起作用? 有没有其他方法可以实现这一目标?

谢谢!

--------------------------更新--------- --------------------------

谢谢!使用 allow_any_instance_of(M) 解决了这个问题。 我的下一个问题是 - 如果我使用 prepend 而不是 include 会发生什么?见以下代码:

module M
  def foo
    super
  end
end

module A
  class << self
    prepend M

    def foo
      :A
    end
  end
end

describe "trying to stub the included method" do
  before  allow_any_instance_of(M).to receive(:foo).and_return(:bar) 

  it "should be stubbed when calling A" do
    expect(A.foo).to eq :bar
  end
end 

这一次,使用 allow_any_instance_of(M) 会导致无限循环。这是为什么?

【问题讨论】:

【参考方案1】:

请注意,您不能直接致电M.foo!您的代码似乎只是因为您嘲笑 M.foo 以返回 :bar 才有效。

当您打开 A 元类 (class &lt;&lt; self) 以包含 M 时,您必须模拟 M 的任何实例,这将添加到您的 before 块中:

allow_any_instance_of(M).to receive(:foo).and_return(:bar)

module M
  def foo
    :M
  end
end

module A
  class << self
    include M

    def foo
      super
    end
  end
end

describe "trying to stub the included method" do
  before do
    allow(M).to receive(:foo).and_return(:bar)
    allow_any_instance_of(M).to receive(:foo).and_return(:bar)
  end


  it "should be stubbed when calling M" do
    expect(M.foo).to eq :bar
  end

  it "should be stubbed when calling A" do
    expect(A.foo).to eq :bar
  end
end

【讨论】:

这行得通。显然,与allow 不同,allow_any_instance_of 不需要在对象上定义方法。 我认为这只是帮助我解决了 5 个多小时的问题。谢谢! Cf., expect_any_instance_of... 这让我走上了正轨

以上是关于有没有办法用 Rspec 存根包含模块的方法?的主要内容,如果未能解决你的问题,请参考以下文章

RSpec 中的测试模块

无法使用 rspec 存根辅助方法

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

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

当方法被意外调用的次数超过指定次数时,有没有办法从 rspec 获取堆栈跟踪?

Rspec 模拟和存根与期望混淆