rspec: как заглушить метод экземпляра, вызываемый конструктором - PullRequest
31 голосов
/ 25 ноября 2008
class A
  def initialize
    @x = do_something
  end

  def do_something
    42
  end
end

Как я могу заглушить do_something в rspec, перед тем, как будет вызвана исходная реализация (таким образом, присваивая 42 @x)? И без изменения реализации, конечно.

Ответы [ 11 ]

22 голосов
/ 26 ноября 2008

Вот коммит, который добавляет функцию к rspec - это было 25 мая 2008 года. С этим вы можете сделать

A.any_instance.stub(do_something: 23)

Однако в последней версии rspec для гемов (1.1.11, октябрь 2008 г.) этот патч отсутствует.

В этом билете указано, что его вытащили по причинам технического обслуживания, а альтернативного решения пока не предоставлено.

Не похоже, что вы можете сделать это на данный момент. Вам придется взломать класс вручную, используя alias_method или somesuch.

16 голосов
/ 25 декабря 2009

Я нашел это решение на http://pivotallabs.com/introducing-rr/

new_method = A.method(:new)

A.stub!(:new).and_return do |*args|
  a = new_method.call(*args)
  a.should_receive(:do_something).and_return(23)
  a
end
11 голосов
/ 25 ноября 2008

Я не знаю, как это сделать в фиктивной среде spec, но вы легко можете поменять его на mocha, чтобы сделать следующее:

# should probably be in spec/spec_helper.rb
Spec::Runner.configure do |config|
  config.mock_with :mocha
end

describe A, " when initialized" do
  it "should set x to 42" do
    A.new.x.should == 42
  end
end

describe A, " when do_something is mocked" do
  it "should set x to 23" do
    A.any_instance.expects(:do_something).returns(23)
    A.new.x.should == 23
  end
end
5 голосов
/ 25 ноября 2008

или с RR :

stub.any_instance_of(A).do_something { 23 }
3 голосов
/ 14 июля 2016

В последней версии RSpec на сегодня - 3.5 вы можете:

allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
2 голосов
/ 21 августа 2012

В RSpec 2.6 или более поздней версии вы можете использовать

A.any_instance.stub(do_something: 23)

См. документы для более подробной информации. (Спасибо rogerdpack за указание на то, что это теперь возможно - я думал, что это заслуживает своего собственного ответа)

2 голосов
/ 22 апреля 2010

Мне нравится ответ Дениса Барушева. И я хотел бы предложить только одно косметическое изменение, которое делает переменную new_method ненужной. Rspec работает с заглушенными методами, поэтому к ним можно обращаться с префиксом proxied_by_rspec__:


A.stub!(:new).and_return do |*args|
  a = A.proxied_by_rspec__new(*args)
  a.should_receive(:do_something).and_return(23)
  a
end
0 голосов
/ 10 июня 2012

Gem rspec_candy поставляется с вспомогательным методом stub_any_instance, который работает как в RSpec 1, так и в RSpec 2.

0 голосов
/ 01 мая 2012

Вот идея, которая может быть не очень элегантной, но, в принципе, сработает:

Создайте крошечный класс, который наследует класс, который вы хотите проверить, переопределите метод initialize и вызовите super после , создав заглушки в инициализации, например:

it "should call during_init in initialize" do
  class TestClass < TheClassToTest
    def initialize
      should_receive(:during_init)
      super
    end
  end
  TestClass.new
end

И вот, пожалуйста! Я только что успешно использовал это в одном из моих тестов.

0 голосов
/ 11 октября 2009

Чтобы заглушить метод экземпляра, вы можете сделать что-то вроде этого:

before :each do
  @my_stub = stub("A")
  @my_stub.should_receive(:do_something).with(no_args()).and_return(42)
  @my_stub.should_receive(:do_something_else).with(any_args()).and_return(true)
  A.stub(:new).and_return(my_stub)
end

Но, как указал pschneider, просто верните 42 на новом: A.stub(:new).and_return(42) или что-то в этом роде.

...