Hi I am new to rspec and was trying to figure out what is the difference between passing a block to expect{ } and just using expect( )
Here is a trivial example
require "rails_helper"
RSpec.describe "Test",type: :model do
it "testing count" do
arr=[1,2,3]
expect{arr<<1}.to change{arr.count}.by(1)
end
end
This runs fine but when I do this instead
require "rails_helper"
RSpec.describe "Test",type: :model do
it "testing count" do
arr=[1,2,3]
expect(arr<<1).to change{arr.count}.by(1)
end
end
It throws an error
Failures:
1) Test testing count
Failure/Error: expect(arr<<1).to change{arr.count}.by(1)
expected `arr.count` to have changed by 1, but was not given a block
# ./spec/models/test_spec.rb:6:in block (2 levels) in <top (required)>
And even when I don't use a block with change it gives me an error
require "rails_helper"
RSpec.describe "Test",type: :model do
it "testing count" do
arr=[1,2,3]
expect{arr<<1}.to change(arr.count).by(1)
end
end
Failures:
1) Test testing count
Failure/Error: expect{arr<<1}.to change(arr.count).by(1)
ArgumentError:
`change` requires either an object and message (`change(obj, :msg)`) or a block (`change { }`). You passed an object but no message.
Can someone explain why is it happening??
The expect(...)
syntax is used to expect that the return value of the statement in the parentheses matches a certain condition, like:
expect(result).to eq(3)
expect(list).not_to be_empty
expect(string).to match(/regexp/)
expect(1..10).to cover(3)
The expect { ... }
runs the block and doesn't really care about the return value of the block, but instead about the side-effects of running the code in the block. Like that another value changes by running the block or that an exception is raised.
expect { api_request }.to raise_error(NotFoundError)
expect { object.action }.to change(object, :value).from(old).to(new)
expect { actual }.to output("some output").to_stdout
Find more examples in the RSpec docs
In your example
expect { array << 1 }.to change { array.count }.by(1)
because a side-effect of pushing a value into an array is that the count of elements in the array changes. But
expect(array << 1).to change { array.count }.by(1)
does not work, because the return value of expect(array << 1)
is [1, 2, 3, 1]
and this syntax does not support the change
matcher.