rspec: как заглушить метод экземпляра, вызываемый конструктором?
Вопрос
class A
def initialize
@x = do_something
end
def do_something
42
end
end
Как я могу заглушить do_something
в rspec до вызова исходной реализации (таким образом, назначив 42 для @x
)? И без изменения реализации, конечно.
Решение
Вот коммит, который добавляет функцию в rspec - это было 25 мая 2008 года. С этим вы можете сделать
A.any_instance.stub(do_something: 23)
Однако в последней версии rspec для гемов (1.1.11, октябрь 2008 г.) этот патч отсутствует. Р>
В этом билете указано, что они вытащили его по причинам технического обслуживания, а альтернативное решение пока не предоставлено.
Не похоже, что вы можете сделать это на данный момент. Вам придется взломать класс вручную, используя alias_method или somesuch.
Другие советы
Я нашел это решение на http://pivotallabs.com/introduction-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
Я не знаю, как это сделать в фиктивной среде 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
или с RR :
stub.any_instance_of(A).do_something { 23 }
В последней версии RSpec на сегодня - 3.5 вы можете:
allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
Мне очень нравится ответ Дениса Барушева. И я хотел бы предложить только одно косметическое изменение, которое делает переменную 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
В RSpec 2.6 или новее вы можете использовать
A.any_instance.stub(do_something: 23)
См. Документы для более подробной информации. (Спасибо rogerdpack за указание на то, что это теперь возможно - я думал, что это заслуживает своего собственного ответа)
Чтобы заглушить метод экземпляра, вы можете сделать что-то вроде этого:
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)
или что-то в этом роде.
Вот идея, которая может быть не очень элегантной, но, в принципе, сработает:
Создайте крошечный класс, который наследует класс, который вы хотите протестировать, переопределите метод 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
И вот, пожалуйста! Я только что успешно использовал это в одном из моих тестов.
Gem rspec_candy поставляется с вспомогательным методом stub_any_instance
, который работает как в RSpec 1 и RSpec 2.
В моей версии rspec (1.2.2) я могу сделать это:
A.should_receive(:new).and_return(42)
Я знаю, что, возможно, уже поздно отвечать на оригинальный постер, но я все равно отвечу на него для дальнейшего использования, так как пришел сюда с тем же вопросом, но понял, что он работает над последней версией rspec.