ejoubaud
ejoubaud

Reputation: 5241

RSpec: assert message calls on stub/spy arguments

Is there an RSpec way to do assertions on the return value of arguments passed to other objects?

Say I'm expecting Checker#notify to call Mailer.send(report), and I want to assert that report.errors_count will return 2 ?

I got very close with this:

expect(Mailer).to have_received(:send).with(hash_including(:errors_count => 2))

But that will only work with a hash. What if I'm passing a PORO or a Struct. duck_type() also comes pretty close but just asserts the method is defined, not its return value (which is kind of the important part here).

PS: Ideally I'd like to avoid doing something like this:

expected_report = Report.new.tap{|r| r.errors_count = 2}
expect(Mailer).to have_received(:send).with(expected_report)
  1. I'd rather test interfaces and not depend on the actual class used to generate the report (quack quack)
  2. If Checker adds other states I don't care about, this will break

Upvotes: 1

Views: 1060

Answers (2)

ejoubaud
ejoubaud

Reputation: 5241

Got it! You can pass a block to receive. It takes the arguments passed to the method, so you can test anything on them:

expect(Mailer).to receive(:send_mail) do |report|
  expect(report.error_count).to be(2)
end

Edit: This doesn't seem to work with the spy (have_received) version. The test will be green but the block won't be evaluated.

Upvotes: 4

Davd_R
Davd_R

Reputation: 384

Try Rspec's #and_call_original

Upvotes: 1

Related Questions