rspec: ¿Cómo stub un método de instancia llamado por constructor?
class A
def initialize
@x = do_something
end
def do_something
42
end
end
¿Cómo puedo stub do_something
en rspec, antes de que se llame a la implementación original (asignando así 42 a @x
)? Y sin cambiar la implementación, por supuesto.
11 answers
Aquí está el commit que agrega la característica a rspec - Esto fue el 25 de mayo de 2008. Con esto se puede hacer
A.any_instance.stub(do_something: 23)
Sin embargo, la última versión de gema de rspec (1.1.11, octubre de 2008) no tiene este parche.
Este ticket indica que lo arrancaron por razones de mantenimiento, y aún no se ha proporcionado una solución alternativa.
No parece que puedas hacerlo en este punto. Tendrás que hackear la clase manualmente usando alias_method o algo así.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-21 12:28:55
He encontrado esta solución en 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-19 20:59:11
No se como hacer eso en el mock framework de spec, pero puedes cambiarlo fácilmente por mocha para hacer lo siguiente:
# 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-25 03:50:18
O con RR:
stub.any_instance_of(A).do_something { 23 }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-25 04:16:50
En la última versión de RSpec a partir de hoy-3.5 usted puede:
allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-14 09:39:52
Me gusta la respuesta de Denis Barushev. Y me gustaría sugerir sólo un cambio cosmético que hace new_method
variable innecesaria. Rspec hace munge en métodos stubbed, de modo que se puede acceder a ellos con proxied_by_rspec__
prefijo:
A.stub!(:new).and_return do |*args|
a = A.proxied_by_rspec__new(*args)
a.should_receive(:do_something).and_return(23)
a
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-30 06:59:38
En RSpec 2.6 o posterior puede usar
A.any_instance.stub(do_something: 23)
Ver los documentos para más detalles. (Gracias a rogerdpack por señalar que esto ahora es posible-pensé que merecía una respuesta propia)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:33:32
Para stub un método de instancia, puedes hacer algo como esto:
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
Pero como pschneider señaló, solo devuelve 42 en nuevo con:
A.stub(:new).and_return(42)
o algo en ese sentido.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-11 05:25:56
Aquí hay una idea que puede no ser muy elegante, pero básicamente seguro que funcionará:
Cree una clase pequeña que hereda la clase que desea probar, anule el método initialize y llame super
después de haber creado los stubs en la inicialización, así:
it "should call during_init in initialize" do
class TestClass < TheClassToTest
def initialize
should_receive(:during_init)
super
end
end
TestClass.new
end
Y ahí lo tienes! Acabo de usar esto con éxito en una de mis pruebas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-01 18:24:59
La gema rspec_candy viene con un método auxiliar stub_any_instance
que funciona tanto en RSpec 1 como en RSpec 2.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-10 08:50:28
En mi versión de rspec (1.2.2) puedo hacer esto:
A.should_receive(:new).and_return(42)
Sé que probablemente es demasiado tarde para responder al póster original, pero lo respondo de todos modos para futuras referencias, ya que vine aquí con la misma pregunta pero descubrí que estaba trabajando en la última versión de rspec.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-22 17:10:29