有没有一种方法可以使用Rspec框架存根(stub)一个包含模块的方法?

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

在这种情况下为什么存根(stub)不起作用?还有其他实现方式吗?

谢谢!

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

谢谢!使用 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个回答

40
注意,你不能直接调用M.foo!你的代码之所以能够工作是因为你模拟了M.foo返回值为:bar
当你打开A元类(class << 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

1
这很有效。显然,与allow不同,allow_any_instance_of不要求方法在对象上定义。 - Peter Ehrlich
2
我认为这刚刚帮助我解决了五个小时的头痛问题。谢谢! - Derek
2
参考 expect_any_instance_of... 这让我找对了方向。 - Daniel Bidulock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接