Есть ли способ заглушить метод включенного модуля с помощью Rspec?

У меня есть модуль, который включен в другой модуль, и оба они реализуют один и тот же метод. Я хотел бы заглушить метод включенного модуля, что-то вроде этого:

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 и не включаю? см. следующий код:

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) приводит к бесконечному циклу. почему это?


person user3775153    schedule 25.06.2014    source источник


Ответы (1)


Обратите внимание, что вы не можете напрямую вызывать 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
person mdemolin    schedule 25.06.2014
comment
Это работает. По-видимому, в отличие от allow, allow_any_instance_of не требует, чтобы метод был определен для объекта. - person Peter Ehrlich; 03.12.2015
comment
я думаю, что это просто помогло мне решить 5+ часов биться головой о стол. Спасибо! - person Derek; 20.04.2016
comment
Cf., expect_any_instance_of... это поставило меня на правильный путь - person Daniel Bidulock; 31.05.2016