rspec: ¿Cómo tropezar con un método de instancia llamado por el constructor?

StackOverflow https://stackoverflow.com/questions/316294

  •  11-07-2019
  •  | 
  •  

Pregunta

class A
  def initialize
    @x = do_something
  end

  def do_something
    42
  end
end

¿Cómo puedo colocar do_something en rspec, antes de que se llame a la implementación original (asignando 42 a @x )? Y sin cambiar la implementación, por supuesto.

¿Fue útil?

Solución

Aquí está el commit que agrega la función a rspec - Este 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 ticket indica que lo retiraron por razones de mantenimiento, y aún no se ha proporcionado una solución alternativa.

No parece que puedas hacerlo en este momento. Tendrás que hackear la clase manualmente usando alias_method o somesuch.

Otros consejos

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

No sé cómo hacerlo en el marco simulado de las especificaciones, 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

o con RR :

stub.any_instance_of(A).do_something { 23 }

En la última versión de RSpec a partir de hoy - 3.5 puede:

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

Me gusta la respuesta de Denis Barushev. Y me gustaría sugerir solo un cambio cosmético que hace innecesaria la variable new_method . Rspec analiza los métodos apagados, para que se pueda 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

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)

Para tropezar con 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, solo devuelve 42 en nuevo con: A.stub (: new) .and_return (42) o algo por el estilo.

Aquí hay una idea que podría no ser muy elegante, pero que seguramente funcionará:

Cree una clase pequeña 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, 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í tienes! Acabo de usar esto con éxito en una de mis pruebas.

La gema rspec_candy viene con un método auxiliar stub_any_instance que funciona en ambos RSpec 1 y RSpec 2.

En mi versión de rspec (1.2.2) puedo hacer esto:

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

Sé que probablemente sea demasiado tarde para responder al póster original, pero lo contesto de todos modos para referencia futura, ya que vine aquí con la misma pregunta pero descubrí que estaba funcionando en la última versión de rspec.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top