ruby - tipos - que es una clase en programacion
rspec: ¿Cómo resguardar un método de instancia llamado por el constructor? (11)
Encontré 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
class A
def initialize
@x = do_something
end
def do_something
42
end
end
¿Cómo puedo do_something
en rspec antes de llamar a la implementación original (asignando 42 a @x
)? Y sin cambiar la implementación, por supuesto.
No sé cómo hacer eso en el marco simulado de las especificaciones, pero puedes cambiarlo fácilmente para que Mocha haga 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
o con RR :
stub.any_instance_of(A).do_something { 23 }
En mi versión de rspec (1.2.2) puedo hacer esto:
A.should_receive(:new).and_return(42)
Sé que 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 descubro que estaba trabajando en la última versión de rspec.
Para resguardar un método de instancia, puede 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 señaló pschneider, simplemente devuelve 42 en new con: A.stub(:new).and_return(42)
o algo por el estilo.
Me gusta la respuesta de Denis Barushev. Y me gustaría sugerir un solo cambio cosmético que hace que la variable new_method
sea innecesaria. Rspec aplica métodos trozados, de modo que se puede acceder con el prefijo 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
Aquí hay una idea que puede no ser muy elegante, pero que básicamente funciona:
Cree una pequeña clase que herede la clase que desea probar, anule el método de inicialización y llame a super
después de haber creado los apéndices en la inicialización, de esta forma:
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í tienes! Acabo de usar esto con éxito en una de mis pruebas.
La gema rspec_candy viene con un método de ayuda stub_any_instance
que funciona tanto en RSpec 1 como en RSpec 2.
Aquí está la confirmación que agrega la característica a rspec - Esto fue el 25 de mayo de 2008. Con esto puedes 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 boleto indica que lo sacaron 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 somesuch.
En la última versión de RSpec a partir de hoy - 3.5 puedes:
allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
En RSpec 2.6 o posterior, puedes 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)