Как я могу отключить глобальную функцию, вызываемую из конструктора?

#ruby #rspec #rspec-mocks

#ruby #rspec #rspec-издевается

Вопрос:

Я пытаюсь отключить глобальную функцию, вызываемую из конструктора. Я использую Rspec и Rspec-mocks. Вот код для тестирования:

 def foo
  'foo'
end

class Bar
  def initialize
    @bar = foo
  end

  def bar
    @bar
  end
end
  

И вот тест:

 describe 'bar'
  it 'calls foo' do
    expect(self).to receive(:foo) { 'bar' }

    expect(Bar.new.bar).to eq('bar')
  end
end
  

Тест завершается ошибкой со следующим сообщением:

      Failure/Error: expect(Bar.new.bar).to eq('bar')

       expected: "bar"
            got: "foo"

       (compared using ==)
  

Как я могу отключить глобальную функцию? foo

PS: expect(self).to receive(:foo) { 'bar' } работает должным образом, если foo вызывается из другой глобальной функции.

Ответ №1:

Вероятно, самым простым решением является uses #allow_any_instance_of , которое работает, потому что «глобальные» функции на самом деле Kernel являются методами в Ruby. Но поскольку документация не рекомендует заглушать классы глобально, я подумал, что, по крайней мере, предложу альтернативу:

 def foo
  'foo'
end

class Bar
  def self.get_foo
    foo
  end

  def initialize
    @bar = self.class.get_foo
  end

  def bar
    @bar
  end
end
  

и

 describe Bar do
  it 'gets foo' do
    expect(Bar).to receive(:get_foo).and_return('bar')

    expect(Bar.new.bar).to eq('bar')
  end
end
  

Конечно, если возможно, было бы лучше отказаться от Kernel метода и просто использовать метод класса.

Ответ №2:

 allow_any_instance_of(Bar).to receive(:foo) { 'bar' }