Подтвердить что ты не робот

Rspec: Как заглушить метод экземпляра, вызываемый конструктором?

class A
  def initialize
    @x = do_something
  end

  def do_something
    42
  end
end

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

4b9b3361

Ответ 1

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

A.any_instance.stub(do_something: 23)

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

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

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

Ответ 2

Я нашел это решение на 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

Ответ 3

Я не знаю, как это сделать в спецификации mock framework, но вы можете легко поменять его на 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

Ответ 4

или RR:

stub.any_instance_of(A).do_something { 23 }

Ответ 5

Мне нравится Денис Барушев. И я хотел бы предложить только одно косметическое изменение, которое делает переменную 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

Ответ 6

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

A.any_instance.stub(do_something: 23)

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

Ответ 7

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

allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")

Ответ 8

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

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

Но, как указал Пшнейдер, просто верните 42 на новый с помощью: A.stub(:new).and_return(42) или что-то в этом роде.

Ответ 9

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

Создайте крошечный класс, который наследует класс, который вы хотите протестировать, переопределите метод 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

И вот ты! Я просто использовал это успешно в одном из моих тестов.

Ответ 10

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

Ответ 11

В моей версии rspec (1.2.2) я могу сделать это:

A.should_receive(:new).and_return(42)

Я знаю, что, возможно, поздно ответить на оригинальный плакат, но я все равно отвечаю на него в будущем, поскольку я пришел сюда с тем же вопросом, но выяснил, что он работал над последней версией rspec.