Question

class A
  def initialize
    @x = do_something
  end

  def do_something
    42
  end
end

Comment puis-je remplacer do_something dans rspec avant l'appel de l'implémentation d'origine (attribuant ainsi 42 à @x )? Et sans changer la mise en œuvre, bien sûr.

Était-ce utile?

La solution

Voici le commit qui ajoute la fonctionnalité à rspec - Cela a été le 25 mai 2008. Avec cela, vous pouvez faire

A.any_instance.stub(do_something: 23)

Cependant, la dernière version gem de rspec (1.1.11, octobre 2008) ne contient pas ce correctif.

Ce ticket indique qu'ils l'ont retiré pour des raisons de maintenance et qu'aucune autre solution n'a encore été fournie.

Ne semble pas pouvoir le faire à ce stade. Vous devrez pirater la classe manuellement en utilisant alias_method ou quelque chose de ce genre.

Autres conseils

J'ai trouvé cette solution sur 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

Je ne sais pas comment faire cela dans le cadre fictif de spec, mais vous pouvez facilement l'échanger pour que mocha effectue les opérations suivantes:

# 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

ou avec RR :

stub.any_instance_of(A).do_something { 23 }

Dans la dernière version de RSpec d’aujourd’hui - 3.5, vous pouvez:

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

J'aime bien la réponse de Denis Barushev. Et je voudrais suggérer un seul changement cosmétique rendant inutile la variable new_method . Rspec utilise les méthodes décomposées pour pouvoir y accéder avec le préfixe 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

Dans RSpec 2.6 ou version ultérieure, vous pouvez utiliser

A.any_instance.stub(do_something: 23)

Voir la documentation pour plus de détails. (Merci à rogerdpack d'avoir souligné que cela est désormais possible - je pensais que cela méritait une réponse en soi)

Pour stub une méthode d'instance, vous pouvez faire quelque chose comme ceci:

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

Mais comme l'a souligné pschneider, revenez simplement sur 42 avec le nouveau avec: A.stub (: new) .and_return (42) ou quelque chose de similaire.

Voici une idée qui pourrait ne pas être très élégante mais qui fonctionnera à coup sûr:

Créez une petite classe qui hérite de la classe que vous souhaitez tester, substituez la méthode initialize et appelez super après avoir créé les stubs lors de l'initialisation, comme suit:

it "should call during_init in initialize" do
  class TestClass < TheClassToTest
    def initialize
      should_receive(:during_init)
      super
    end
  end
  TestClass.new
end

Et voilà! Je viens de l'utiliser avec succès dans l'un de mes tests.

La rspec_candy est fournie avec une méthode d'assistance stub_any_instance qui fonctionne dans les deux cas. RSpec 1 et RSpec 2.

Dans ma version de rspec (1.2.2), je peux le faire:

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

Je sais qu'il est probablement trop tard pour répondre à l'affiche originale, mais j'y réponds quand même pour référence future, car je suis arrivé ici avec la même question, mais sachez qu'il travaillait sur la dernière version de rspec.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top