Search code examples
ruby-on-railsrubyrspecrspec-rails

Using the one-liner syntax for controller specs


I'm trying to write terse tests for an API controller, but I'm having trouble with the "one-liner" syntax offered by RSpec.

I'm overriding the subject explictly to refer to the action of posting rather than the controller:

let (:params) { some_valid_params_here }
subject { post :create, params }

When I use the one-liner syntax to test http_status, it works fine:

it { is_expected.to have_http_status(:created) }
# pass!

But when I try to use it for a different expectation, it blows up:

it { is_expected.to change{SomeActiveRecordModel.count}.by(1) }
# fail! "expected result to have changed by 1, but was not given a block"

Notably, when I run this second expectation in a longer form, calling on subject explictly, it works:

it "creates a model" do
  expect{ subject }.to change{SomeActiveRecordModel.count}.by(1)
end
# pass

Is this just a weakness of the one-liner syntax, that it can't handle this more complicated expression? Or have I misunderstood something about how subject is inferred into these tests?

(NB: I know that setting the subject to an action has some detractors, and I'm happy to hear opinions, but that isn't the aim of this question).


Solution

  • You can do it like this subject { -> { post :create, params } } and then it { is_expected.to change(SomeActiveRecordModel, :count).by(1) }

    Here you have very nice discussion about this github_topic