Reputation: 519
I recently learn about rspec test in rails and as following the link https://relishapp.com/rspec/rspec-core/v/3-6/docs/subject/explicit-subject that said "The subject
is memoized within an example but not across examples " with the code below:
RSpec.describe Array do
# This uses a context local variable. As you can see from the
# specs, it can mutate across examples. Use with caution.
element_list = [1, 2, 3]
subject { element_list.pop }
it "is memoized across calls (i.e. the block is invoked once)" do
expect {
3.times { subject }
}.to change{ element_list }.from([1, 2, 3]).to([1, 2])
expect(subject).to eq(3)
end
it "is not memoized across examples" do
expect{ subject }.to change{ element_list }.from([1, 2]).to([1])
expect(subject).to eq(2)
end
end
Can anyone explain to me:
Thank you.
Upvotes: 1
Views: 4107
Reputation: 5213
First, by way of clarification, the RSpec subject
helper is nothing more than a special case of RSpec's let
helper. Using subject { element_list.pop }
is equivalent to let(:subject) { element_list.pop }
.
Like any other let
, subject
is evaluated once per example. If subject
has a value, that value is returned without re-evaluation. The general term for this is "memoization."
Ruby's ||=
operator does the same thing. It says, "if a value exists in that variable, return the value, otherwise evaluate the expression, assign it to the variable, and return the value." You can see this concept in action in the console with this example:
>> element_list = [1, 2, 3]
>> subject ||= element_list.pop
=> 3
>> element_list
=> [1, 2]
>> subject ||= element_list.pop
=> 3
>> element_list
=> [1, 2]
>> subject
=> 3
The fact that subject
is not memoized across examples means that its value is reset when a new example is executed. So for your next it
block, subject
will start out unassigned and its expression will be re-evaluated when it is first used in that next it
block.
Upvotes: 2