RSpec: jak sprawdzić, czy metoda została wywołana?

112

Pisząc testy RSpec, piszę dużo kodu, który wygląda tak, aby upewnić się, że metoda została wywołana podczas wykonywania testu (ze względu na argument, powiedzmy, że tak naprawdę nie mogę przesłuchać stanu obiektu po wywołaniu, ponieważ operacja, którą wykonuje metoda, nie jest łatwa do zobaczenia).

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

Chcę wiedzieć: czy jest dostępna ładniejsza składnia niż ta? Czy brakuje mi jakiejś fajnej niesamowitości RSpec, która zredukowałaby powyższy kod do kilku wierszy? should_receivewydaje się, że powinien to zrobić, ale czytając dalej, wydaje się, że to nie jest dokładnie to, co robi.

Mikey Hogarth
źródło
3
Sprawdź tutaj: stackoverflow.com/questions/1328277/…
kddeisz
@Peter Alfvin OP prosił o włączenie składni should_receive, więc pomyślałem, że to pytanie pomoże.
kddeisz

Odpowiedzi:

141
it "should call 'bar' with appropriate arguments" do
  expect(subject).to receive(:bar).with("an argument I want")
  subject.foo
end
wacko
źródło
1
Przepraszamy, nie rozumiem, w jaki sposób ten format „to .. odbierać (: bar)” sprawdza wartość „named_bar” w tym przykładzie. Czy możesz mi to wyjaśnić?
ekodowanie 5
2
@ ecoding5 no. Tak nie jest i nie powinno się tego sprawdzać called_bar. To była tylko flaga zapewniająca, że ​​metoda została wywołana, ale z expect(...).to receive(...)tobą już to obejmuje. To jest bardziej przejrzyste i semantyczne
wacko
@wacko oooh, rozumiem, dzięki za wyjaśnienie tego. Nie złapałem tego za pierwszym razem.
ekodowanie 5
102

W nowej rspec expectskładni wyglądałoby to tak:

expect(subject).to receive(:bar).with("an argument I want")
Uri Agassi
źródło
37

Poniższe powinno działać

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

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

bjhaid
źródło
Dziękuję - otrzymałem komunikat „NoMethodError” has_received? - myślę, że może to mieć związek z wersjami rspec. Znalazłem inne rozwiązanie, które zadziałało (to zaznaczone jako poprawne powyżej)
Mikey Hogarth
@MikeyHogarth Ta odpowiedź sugerowała have_received(po fakcie podejście „szpiegów”), a nie has_received, co nie jest częścią żadnej znanej mi wersji RSpec.
Peter Alfvin,
2

Aby w pełni zachować zgodność ze składnią RSpec ~> 3.1 i rubocop-rspecdomyślną opcją reguły RSpec/MessageSpies, oto co możesz zrobić z spy:

Oczekiwania dotyczące wiadomości umieszczają oczekiwanie przykładu na początku, zanim wywołasz testowany kod. Wielu programistów woli używać wzorca aranżuj-działaj-potwierdzaj (lub określ-kiedy-wtedy) do tworzenia struktury testów. Szpiedzy są alternatywnym typem podwójnych testów, które obsługują ten wzorzec, pozwalając ci oczekiwać, że wiadomość została odebrana po fakcie, używając funkcji have_received.

# arrange.
invitation = spy('invitation')

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

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

Jeśli nie używasz rubocop-rspec lub nie używasz opcji domyślnej. Możesz oczywiście użyć standardu RSpec 3 z oczekiwaniem.

dbl = double("Some Collaborator")
expect(dbl).to receive(:foo).with("[email protected]")
Yi Zeng
źródło