web-dev-qa-db-fra.com

Dans RSpec, existe-t-il une méthode équivalente à "unstub" mais pour "should_receive"?

Existe-t-il une méthode pour supprimer tout stubbing et moquerie lors de l'utilisation de RSpec?

Exemple:

RestClient.should_receive(:delete).with("http://www.example.com")
...
... 

# this will remove the mocking of "should_receive" and 
# restore the proper "delete" method on "RestClient".
RestClient.mocking_reset

(mocking_reset est mon nom fictif pour la fonctionnalité requise).

Je sais qu'il existe la méthode "unstub" qui réinitialise les "stubs" mais pas les "should_receive".

Alors, existe-t-il une méthode équivalente à "unstub" mais pour "should_receive"?

Panayotis

39
p.matsinopoulos

Pour le moment (rspec-mocks 2.10.1) il n'y a pas de méthode équivalente à unstub mais pour should_receive. Vous pouvez réinitialiser tous les talons et les simulations à l'aide de rspec_reset, et vous pouvez également écrire des hacks sales pour supprimer une attente particulière (que je ne recommanderais pas).

Voici un exemple de suppression de tous les talons et attentes d'un objet:

describe "resetting stubs and expectations with rspec_reset" do
  before do
    @person = mock('person')
    @person.should_receive(:poke)
  end

  it "should not fail when we reset all stubs and expectations" do
    @person.rspec_reset
  end
end

Notez que cette méthode est annotée dans le code source rspec comme @private, ce qui signifie que vous devez éviter de l'utiliser plus que ce qui est absolument nécessaire et cela pourrait se casser dans les futures versions de rspec sans avertissement. Cependant, il est assez largement utilisé dans les spécifications de rspec lui-même, il semble donc moins probable que cela soit bientôt obsolète.

Après avoir fouillé un peu plus dans le code rspec-mocks, vous pouvez bien sûr faire quelque chose de vraiment méchant et supprimer vous-même la seule attente spécifique:

# Works in rspec 2.10.1
describe "removing an expectation with an ugly hack" do
  before do
    @person = mock('person')
    @person.should_receive(:poke)
  end

  it "should not fail after we hack rspec by violating every law of good programming, ever" do
    @person.instance_variable_get(:@mock_proxy).instance_variable_get(:@method_double)[:poke].clear
  end
end

C'est vraiment mauvais car il viole l'encapsulation du package de test rspec et vous ne devriez pas le faire. Au lieu de cela, si vous aviez vraiment une raison impérieuse de supprimer une attente particulière, la bonne chose à faire serait d'ajouter une méthode publique en amont dans rspec-mocks qui ajoute une méthode parallèle à unstub mais pour supprimer des attentes spécifiques. Il serait probablement situé ici (notez également la définition de stub et unstub dans ce fichier):

https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/methods.rb

Avant de sortir et d'utiliser l'une des suggestions ci-dessus pour supprimer l'attente, vous pouvez envisager si vos spécifications doivent vraiment le faire ou si elles doivent être refactorisées. En utilisant should_receive est une assertion sur votre code, et vous devriez généralement essayer de créer des exemples (ie it blocs) qui n'affirment qu'une seule chose. Je serais très curieux de savoir pourquoi vous avez besoin de quelque chose comme rspec_reset sauf si vous essayez d'en faire trop dans la configuration globale (par exemple before :each ou avant: tous les blocs), ou si vos exemples essaient d'en faire trop (c'est-à-dire avec plusieurs assertions dans un seul exemple).

La seule exception à cela peut bien sûr être dans la suite de tests de rspec-mocks, où rspec_reset est utilisé pour réinitialiser l'état entre des exemples qui testent la fonctionnalité d'application de stubs et de mocks. À moins que vous ne le fassiez, il est probable que vos tests pourraient être améliorés pour ne pas s'appuyer sur les réinitialisations globales des talons et des simulations sur un objet.

J'espère que cela vous aide et faites-le moi savoir si vous pensez qu'il existe un argument légitime pour ajouter une méthode équivalente à unstub mais pour les attentes des messages (c'est-à-dire après avoir utilisé should_receive). Si je suis convaincu que c'est une chose correcte à faire, j'envisagerais d'ajouter cette méthode et de proposer qu'elle soit ajoutée en amont. Peut-être que ce serait appelé unset_expectation? N'hésitez pas également à utiliser les instructions dans le code et les structures internes ci-dessus pour créer vous-même une demande d'extraction pour rspec-mocks, et nous verrons si elle est acceptée pour créer une maquette équivalente à unstub .

30
Justin Leitgeb

Vous pouvez remplacer certaines moqueries précédentes par:

expect(RestClient).to receive(:delete).and_call_original

Ou si ce n'était pas une attente, juste un simple bout:

allow(RestClient).to receive(:delete).and_call_original

N'oubliez pas qu'il existe également expect_any_instance_of et allow_any_instance_of.

44
Waiting for Dev...

Pour RSpec> = 2.14, la réponse acceptée ne fonctionnera plus. Je vous renvoie à la réponse de Bernhard Köhler sur ce sujet (reproduit ci-dessous pour éviter la pourriture des liens): méthode non définie `rspec_reset 'avec rspec version 2.14

La méthode de réinitialisation n'existe pas dans RSpec 2.14. Il s'agit plutôt d'une méthode d'assistance définie dans le fichier spec_helper.rb pour le projet rspec-mocks.

module VerifyAndResetHelpers
  def verify(object)
    RSpec::Mocks.proxy_for(object).verify
  end

  def reset(object)
    RSpec::Mocks.proxy_for(object).reset
  end
end

Vous pouvez voir que cette méthode délègue l'action de réinitialisation au proxy sous-jacent au lieu de la coller à la définition de classe de l'objet en question.

10
JellicleCat