Rspec Will Be Expected To
RSpec - will_be_expected_to
One of the coolest things about RSpec is the ability to put our expectations in form of a one-liner. It is relatively simple, all you have to do is create a subject of the test and make expectation against it.
RSpec.describe Array do
describe "#pop" do
subject { [1, 2, 3, 4].pop }
it { is_expected.to eq(4) }
end
end
A suite written in that form is short, concise, and easy to follow.
So far so good. Array#pop
despite returning the last value also removes the item from the original array, thus lower the size by 1. Let’s test that out.
RSpec.describe Array do
subject(:array) { [1, 2, 3, 4] }
describe "#pop" do
subject { array.pop }
it { is_expected.to eq(4) }
it { is_expected.to change(array, :count).from(4).to(3) }
end
end
Drat! RSpec responded with an error
Array#pop should change #count from 4 to 3
Failure/Error: it { is_expected.to change(array, :count).from(4).to(3)
expected #count to have changed from 4 to 3, but was not given a block
The behavior is kinda obvious since we have to have a block if we want to evaluate post-change effects. It boils down to a rewrite that looks something like that:
RSpec.describe Array do
subject(:array) { [1, 2, 3, 4] }
describe "#pop" do
subject { array.pop }
it { is_expected.to eq(4) }
it "changes the count from 4 to 3" do
expect { subject }.to change(array, :count).from(4).to(3)
end
end
end
which works. And at the same time repeats almost literally our expectation in the description. Also, the “style” of writing starts to diverge (which is not such a big deal, though the one-liners version looks more appealing).
How to get that into one-liner syntax?
module SpecHelpers
module WillBeExpected
def will_be_expected
expect { subject }
end
end
end
RSpec.configure do |config|
config.include SpecHelpers::WillBeExpected
end
RSpec.describe Array do
subject(:array) { [1, 2, 3, 4] }
describe "#pop" do
subject { array.pop }
it { is_expected.to eq(4) }
it { will_be_expected.to change(array, :count).from(4).to(3) }
end
end
It is not mind-blowing, mind-bending and hackish solution. It comes strictly from a need of having a concise suite. Concise no matter whether we assert return values or post-effects like changing size, raising an error etc. And I believe that every developer admires consistency, especially gained with a low-cost solution.