In the process of writing tests in Rspec, if you encounter repeated required parameters {...}, you can use let
to write it. This avoids writing a bunch of parameter preparations in advance for each example.
However, I don't quite understand the paradigm of Better Specs. His original code is this:
describe '#type_id' do
before { @resource = FactoryBot.create :device }
before { @type = Type.find @resource.type_id }
it 'sets the type_id field' do
expect(@resource.type_id).to eq(@type.id)
end
end
After using let it becomes the following
describe '#type_id' do
let(:resource) { FactoryBot.create :device }
let(:type) { Type.find resource.type_id }
it 'sets the type_id field' do
expect(resource.type_id).to eq(type.id)
end
end
It looks like the way to call a resource
is pretty much the same, what's the benefit of using let ? What is the function of FactoryBot.create:device
? And I can't see where type
is being called?
CodePudding user response:
The difference is that lets are lazily evaluated and then memoized for the rest of the spec.
So in the first example, first the before blocks run and set the values of @resource and @type, and then the spec runs.
In the second example, the spec runs and when it references 'resource' the let block runs and returns a value, then when 'type' is referenced is runs the let block for that. The let block for type itself references 'resource' so it gets the value for resource that was memoized from the first time resource was referenced.
For what its worth, I disagree that lets are 'better'. My team and I have found that all they do is make specs much harder to understand for very little benefit, and we have removed all use of them in all our projects.
In fact, I consider that most of 'better specs' is actually poor advice, so if you are struggling to understand why something is 'better', you are very much not alone :)