RSpec: come verificare se un metodo è stato chiamato?


112

Durante la scrittura di test RSpec, mi ritrovo a scrivere molto codice simile a questo per assicurarmi che un metodo sia stato chiamato durante l'esecuzione di un test (per amor di discussione, diciamo solo che non posso davvero interrogare lo stato dell'oggetto dopo la chiamata perché l'operazione che il metodo esegue non è facile da vedere l'effetto di).

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

Quello che voglio sapere è: esiste una sintassi migliore di questa? Mi manca qualche stravagante bellezza RSpec che ridurrebbe il codice sopra a poche righe? should_receivesembra che dovrebbe farlo, ma leggendo oltre sembra che non sia esattamente quello che fa.



@Peter Alfvin L'OP chiedeva la sintassi should_receive, quindi ho pensato che quella domanda sarebbe stata d'aiuto.
kddeisz

Risposte:


141
it "should call 'bar' with appropriate arguments" do
  expect(subject).to receive(:bar).with("an argument I want")
  subject.foo
end

1
Spiacenti, non capisco come questo formato di "to .. receive (: bar)" controlli il valore di "called_bar" in questo esempio. Puoi spiegarmelo?
ecoding5

2
@ ecoding5 no. Non lo fa e nessuno dei due dovrebbe controllare called_bar. Era solo una bandiera per garantire che il metodo fosse chiamato, ma con expect(...).to receive(...)te lo stai già coprendo. È più chiaro e semantico
wacko

@wacko oooh, capito, grazie per averlo chiarito. Non l'ho preso la prima volta.
ecoding5


37

Quanto segue dovrebbe funzionare

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

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


Grazie - stavo ricevendo "NoMethodError" has_received? - penso che questo potrebbe avere a che fare con rspec versoins però. Ho trovato un'altra soluzione che ha funzionato per me (quella contrassegnata come corretta sopra)
Mikey Hogarth,

@MikeyHogarth Questa risposta suggeriva have_received(l'approccio "spie" dopo il fatto), no has_received, che non fa parte di nessuna versione di RSpec che io conosca.
Peter Alfvin

2

Per rispettare pienamente la sintassi di RSpec ~> 3.1 e rubocop-rspecl'opzione predefinita di regola per la regola RSpec/MessageSpies, ecco cosa puoi fare con spy:

Le aspettative dei messaggi mettono le aspettative di un esempio all'inizio, prima che tu abbia invocato il codice sotto test. Molti sviluppatori preferiscono usare un pattern arrangiare-agire-asserire (o dare-quando-allora) per strutturare i test. Le spie sono un tipo alternativo di test double che supportano questo modello consentendo di aspettarsi che un messaggio sia stato ricevuto dopo il fatto, utilizzando have_received.

# arrange.
invitation = spy('invitation')

# act.
invitation.deliver("foo@example.com")

# assert.
expect(invitation).to have_received(:deliver).with("foo@example.com")

Se non usi rubocop-rspec o usi un'opzione non predefinita. Puoi, ovviamente, utilizzare RSpec 3 predefinito con aspettativa.

dbl = double("Some Collaborator")
expect(dbl).to receive(:foo).with("foo@example.com")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.