RSpec: Wie teste ich, ob eine Methode aufgerufen wurde?

112

Beim Schreiben von RSpec-Tests schreibe ich viel Code, der so aussieht, um sicherzustellen, dass während der Ausführung eines Tests eine Methode aufgerufen wurde (aus Gründen der Argumentation sagen wir einfach, dass ich den Status nicht wirklich abfragen kann des Objekts nach dem Aufruf, da die Operation, die die Methode ausführt, die Wirkung von) nicht leicht zu erkennen ist.

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

Was ich wissen möchte ist: Gibt es eine schönere Syntax als diese? Vermisse ich eine funky RSpec-Attraktivität, die den obigen Code auf ein paar Zeilen reduzieren würde? should_receiveklingt so, als ob es das tun sollte, aber weiter zu lesen klingt so, als ob es nicht genau das ist, was es tut.

Mikey Hogarth
quelle
3
Überprüfen Sie hier: stackoverflow.com/questions/1328277/…
kddeisz
@Peter Alfvin Das OP hat nach Syntax gefragt should_receive, also dachte ich, diese Frage würde helfen.
kddeisz

Antworten:

141
it "should call 'bar' with appropriate arguments" do
  expect(subject).to receive(:bar).with("an argument I want")
  subject.foo
end
verrückt
quelle
1
Entschuldigung, ich verstehe nicht, wie dieses Format von "to .. receive (: bar)" in diesem Beispiel nach dem Wert von "named_bar" sucht. Kannst du mir das erklären?
ecoding5
2
@ ecoding5 no. Es tut es nicht und sollte es auch nicht überprüfen called_bar. Das war nur ein Flag, um sicherzustellen, dass die Methode aufgerufen wurde, aber mit expect(...).to receive(...)Ihnen wird dies bereits behandelt. Es ist klarer und semantischer
verrückt
@wacko oooh, verstanden, danke für die Aufklärung. Ich habe es nicht das erste Mal gefangen.
ecoding5
102

In der neuen rspec expectSyntax wäre dies:

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

Das Folgende sollte funktionieren

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

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

bjhaid
quelle
Vielen Dank - ich habe "NoMethodError" erhalten has_received? - denke, dies könnte jedoch mit rspec versoins zu tun haben. Ich habe eine andere Lösung gefunden, die für mich funktioniert hat (die oben als korrekt gekennzeichnete)
Mikey Hogarth
@MikeyHogarth Diese Antwort schlug vor have_received(der nachträgliche "Spion " -Ansatz), nicht has_received, was nicht Teil einer Version von RSpec ist, die ich kenne.
Peter Alfvin
2

Um die RSpec ~> 3.1-Syntax und rubocop-rspecdie Standardoption für Regeln vollständig einzuhalten, können Sie Folgendes RSpec/MessageSpiestun spy:

Bei den Nachrichtenerwartungen steht die Erwartung eines Beispiels am Anfang, bevor Sie den zu testenden Code aufgerufen haben. Viele Entwickler bevorzugen die Verwendung eines Arrangement-Act-Assert-Musters (oder eines Given-When-Then-Musters) für die Strukturierung von Tests. Spione sind eine alternative Art von Testdoppel, die dieses Muster unterstützen, indem Sie mithilfe von have_received erwarten können, dass eine Nachricht nachträglich empfangen wurde.

# arrange.
invitation = spy('invitation')

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

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

Wenn Sie nicht rubocop-rspec oder eine nicht standardmäßige Option verwenden. Natürlich können Sie RSpec 3 standardmäßig mit erwarten verwenden.

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