RSpec: how to test if a method was called?
Solution 1
it "should call 'bar' with appropriate arguments" do
expect(subject).to receive(:bar).with("an argument I want")
subject.foo
end
Solution 2
In the new rspec
expect
syntax this would be:
expect(subject).to receive(:bar).with("an argument I want")
Solution 3
The below should work
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
Solution 4
To fully comply with RSpec ~> 3.1 syntax and rubocop-rspec
's default option for rule RSpec/MessageSpies
, here's what you can do with spy
:
Message expectations put an example's expectation at the start, before you've invoked the code-under-test. Many developers prefer using an arrange-act-assert (or given-when-then) pattern for structuring tests. Spies are an alternate type of test double that support this pattern by allowing you to expect that a message has been received after the fact, using have_received.
# arrange.
invitation = spy('invitation')
# act.
invitation.deliver("[email protected]")
# assert.
expect(invitation).to have_received(:deliver).with("[email protected]")
If you don't use rubocop-rspec or using non-default option. You may, of course, use RSpec 3 default with expect.
dbl = double("Some Collaborator")
expect(dbl).to receive(:foo).with("[email protected]")
- Official Documentation: https://relishapp.com/rspec/rspec-mocks/docs/basics/spies
- rubocop-rspec: https://docs.rubocop.org/projects/rspec/en/latest/cops_rspec/#rspecmessagespies
Mikey Hogarth
Updated on April 27, 2020Comments
-
Mikey Hogarth about 4 years
When writing RSpec tests, I find myself writing a lot of code that looks like this in order to ensure that a method was called during the execution of a test (for the sake of argument, let's just say I can't really interrogate the state of the object after the call because the operation the method performs is not easy to see the effect of).
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
What I want to know is: Is there a nicer syntax available than this? Am I missing some funky RSpec awesomeness that would reduce the above code down to a few lines?
should_receive
sounds like it should do this but reading further it sounds like that's not exactly what it does. -
Mikey Hogarth over 10 yearsThank you - I was receiving "NoMethodError" has_received? - think this might be to do with rspec versoins though. I found another solution that worked for me (the one marked correct above)
-
Peter Alfvin over 10 years@MikeyHogarth This answer was suggesting
have_received
(the after the fact "spies" approach), nothas_received
, which is not part of any version of RSpec that I know. -
ecoding5 almost 9 yearsSorry, I'm not understanding how this format of "to .. receive(:bar)" checks for the value of "called_bar" in this example. Can you explain that to me?
-
wacko almost 9 years@ecoding5 no. It doesn't and neither should check for
called_bar
. That was just a flag to ensure that the method was called, but withexpect(...).to receive(...)
you are already covering that. It's more clear and semantic -
ecoding5 almost 9 years@wacko oooh, got it, thanks for the clearing that up. I didn't catch it the first time.