4

I found that assertion method change used in two different ways

expect { createRecord.call }.to change(Record, :count).by(1)

vs

expect { createRecord.call }.to change { Record.count }.by(1)

I tried to dig into source code, and found that passed block will be called if block provided.
Without block message will be "sent" to the receiver.

I was wonder are there some scenarios where one should be preferred over another?

Basin
  • 887
  • 1
  • 14
  • 28
  • 2
    Does this answer your question? [Ruby, rspec Expect error when testing method](https://stackoverflow.com/questions/53053754/ruby-rspec-expect-error-when-testing-method) – anothermh Nov 25 '19 at 03:19
  • 1
    @anothermh, sorry, but no, linked question is about `expect(value)` vs `expect { expression }`, my question is specifically about behavior of `change`, because given expression or values will be evaluated twice. – Basin Nov 25 '19 at 05:39

1 Answers1

3

Not everything maps so neatly to the send approach. For example:

expect { createRecord.call }.to change { Record.count(OtherRecord.param) }.by(1)

Where there's no way to represent that as a simple send(*args) as:

expect { createRecord.call }.to change(Record, :count, OtherRecord.param).by(1)

This evaluates OtherRecord.param as the expect line executes, not at the right before and after interval.

It's provided for feature-completeness and to give you complete control.

In short the block form runs the exact block twice while the other evaluates the arguments once and makes a send call twice.

tadman
  • 208,517
  • 23
  • 234
  • 262