RSpec: how to test if a method was called?

Ruby on-RailsRubyRspec

Ruby on-Rails Problem Overview


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.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

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

Solution 2 - Ruby on-Rails

In the new rspec expect syntax this would be:

expect(subject).to receive(:bar).with("an argument I want")

Solution 3 - Ruby on-Rails

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 - Ruby on-Rails

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]")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMikey HogarthView Question on Stackoverflow
Solution 1 - Ruby on-RailswackoView Answer on Stackoverflow
Solution 2 - Ruby on-RailsUri AgassiView Answer on Stackoverflow
Solution 3 - Ruby on-RailsbjhaidView Answer on Stackoverflow
Solution 4 - Ruby on-RailsYi ZengView Answer on Stackoverflow