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).
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