RSpec: comment tester si une méthode a été appelée?

112

Lors de l'écriture de tests RSpec, je me retrouve à écrire beaucoup de code qui ressemble à ceci afin de m'assurer qu'une méthode a été appelée lors de l'exécution d'un test (pour des raisons d'argument, disons simplement que je ne peux pas vraiment interroger l'état de l'objet après l'appel car l'opération effectuée par la méthode n'est pas facile à voir l'effet de).

describe "#foo"
  it "should call 'bar' with appropriate arguments" do
    called_bar = false
    subject.stub(:bar).with("an argument I want") { called_bar = true }
    subject.foo
    expect(called_bar).to be_true
  end
end

Ce que je veux savoir, c'est: y a-t-il une meilleure syntaxe disponible que celle-ci? Est-ce que je manque une génialité RSpec géniale qui réduirait le code ci-dessus à quelques lignes? should_receiveOn dirait qu'il devrait le faire, mais en lisant plus loin, il semble que ce n'est pas exactement ce qu'il fait.

Mikey Hogarth
la source
3
Vérifiez ici: stackoverflow.com/questions/1328277/…
kddeisz
@Peter Alfvin L'OP demandait la syntaxe should_receive, alors j'ai pensé que cette question aiderait.
kddeisz

Réponses:

141
it "should call 'bar' with appropriate arguments" do
  expect(subject).to receive(:bar).with("an argument I want")
  subject.foo
end
wacko
la source
1
Désolé, je ne comprends pas comment ce format de "pour .. recevoir (: bar)" vérifie la valeur de "appelé_bar" dans cet exemple. Pouvez-vous m'expliquer cela?
ecoding5
2
@ ecoding5 no. Ce n'est pas le cas et aucun des deux ne devrait le vérifier called_bar. C'était juste un drapeau pour s'assurer que la méthode a été appelée, mais avec expect(...).to receive(...)vous, vous couvrez déjà cela. C'est plus clair et sémantique
wacko
@wacko oooh, compris, merci pour cette clarification. Je ne l'ai pas attrapé la première fois.
ecoding5
102

Dans la nouvelle rspec expectsyntaxe, ce serait:

expect(subject).to receive(:bar).with("an argument I want")
Uri Agassi
la source
37

Le ci-dessous devrait fonctionner

describe "#foo"
  it "should call 'bar' with appropriate arguments" do
     subject.stub(:bar)
     subject.foo
     expect(subject).to have_received(:bar).with("Invalid number of arguments")
  end
end

Documentation: https://github.com/rspec/rspec-mocks#expecting-arguments

bjhaid
la source
Merci - Je recevais "NoMethodError" has_received? - Je pense que cela pourrait être lié aux versoins rspec. J'ai trouvé une autre solution qui a fonctionné pour moi (celle marquée comme correcte ci-dessus)
Mikey Hogarth
@MikeyHogarth Cette réponse suggérait have_received(l'approche des "espions" après coup), non has_received, qui ne fait partie d'aucune version de RSpec que je connaisse.
Peter Alfvin
2

Pour vous conformer pleinement à la syntaxe RSpec ~> 3.1 et à rubocop-rspecl'option par défaut de la règle RSpec/MessageSpies, voici ce que vous pouvez faire avec spy:

Les attentes de message mettent l'attente d'un exemple au début, avant que vous n'ayez appelé le code en cours de test. De nombreux développeurs préfèrent utiliser un modèle arrangement-act-assert (ou donné-quand-alors) pour structurer les tests. Les espions sont un autre type de test double qui supporte ce modèle en vous permettant de vous attendre à ce qu'un message ait été reçu après coup, en utilisant have_received.

# arrange.
invitation = spy('invitation')

# act.
invitation.deliver("[email protected]")

# assert.
expect(invitation).to have_received(:deliver).with("[email protected]")

Si vous n'utilisez pas rubocop-rspec ou n'utilisez pas l'option par défaut. Vous pouvez, bien sûr, utiliser RSpec 3 default avec expect.

dbl = double("Some Collaborator")
expect(dbl).to receive(:foo).with("[email protected]")
Yi Zeng
la source