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.

Author: Pedro, 2008-11-25

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í.

 22
Author: Orion Edwards,
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
 16
Author: Denis Barushev,
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
 11
Author: Dustin,
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 }
 5
Author: Chris Lloyd,
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")
 3
Author: Lukasz Muzyka,
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
 2
Author: Serge Balyuk,
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)

 2
Author: David Waller,
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.

 0
Author: bluehavana,
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.

 0
Author: AdrienE,
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.

 0
Author: triskweline,
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.

 -1
Author: phss,
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