Rspec: Как заглушить метод экземпляра, вызываемый конструктором?
class A
def initialize
@x = do_something
end
def do_something
42
end
end
Как я могу заглушить do_something
в rspec до того, как будет вызвана первоначальная реализация (таким образом, присваивая значение 42 на @x
)? И, конечно, без изменения реализации.
Ответы
Ответ 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.