What is difference between let
and a before
block in RSpec?
And when to use each?
What will be good approach (let or before) in below example?
let(:user) { User.make !} let(:account) {user.account.make!} before(:each) do @user = User.make! @account = @user.account.make! end
I studied this stackoverflow post
But is it good to define let for association stuff like above?
let generates a method whose return value is memoized after the first call. This is known as lazy loading because the value is not loaded into memory until the method is called. Here is an example of how let is used within an RSpec test. let will generate a method called thing which returns a new instance of Thing .
I understood the difference between let and let! with a very simple example. Let me read the doc sentence first, then show the output hands on. ... let is lazy-evaluated: it is not evaluated until the first time the method it defines is invoked.
You can't mock an instance variable. You can only mock methods. One option is to define a method inside OneClass that wraps the another_member , and mock that method. However, you don't have to, there is a better way to write and test your code.
The word describe is an RSpec keyword. It is used to define an “Example Group”. You can think of an “Example Group” as a collection of tests. The describe keyword can take a class name and/or string argument.
People seem to have explained some of the basic ways in which they differ, but left out before(:all)
and don't explain exactly why they should be used.
It's my belief that instance variables have no place being used in the vast majority of specs, partly due to the reasons mentioned in this answer, so I won't mention them as an option here.
let blocks
Code within a let
block is only executed when referenced, lazy loading this means that ordering of these blocks is irrelevant. This gives you a large amount of power to cut down on repeated setup through your specs.
One (extremely small and contrived) example of this is:
let(:person) { build(:person) } subject(:result) { Library.calculate_awesome(person, has_moustache) } context 'with a moustache' do let(:has_moustache) { true } its(:awesome?) { should be_true } end context 'without a moustache' do let(:has_moustache) { false } its(:awesome?) { should be_false } end
You can see that has_moustache
is defined differently in each case, but there's no need to repeat the subject
definition. Something important to note is that the last let
block defined in the current context will be used. This is good for setting a default to be used for the majority of specs, which can be overwritten if needed.
For instance, checking the return value of calculate_awesome
if passed a person
model with top_hat
set to true, but no moustache would be:
context 'without a moustache but with a top hat' do let(:has_moustache) { false } let(:person) { build(:person, top_hat: true) } its(:awesome?) { should be_true } end
Another thing to note about let blocks, they should not be used if you're searching for something which has been saved to the database (i.e. Library.find_awesome_people(search_criteria)
) as they will not be saved to the database unless they have already been referenced. let!
or before
blocks are what should be used here.
Also, never ever use before
to trigger execution of let
blocks, this is what let!
is made for!
let! blocks
let!
blocks are executed in the order they are defined (much like a before block). The one core difference to before blocks is that you get an explicit reference to this variable, rather than needing to fall back to instance variables.
As with let
blocks, if multiple let!
blocks are defined with the same name, the most recent is what will be used in execution. The core difference being that let!
blocks will be executed multiple times if used like this, whereas the let
block will only execute the last time.
before(:each) blocks
before(:each)
is the default before block, and can therefore be referenced as before {}
rather than specifying the full before(:each) {}
each time.
It's my personal preference to use before
blocks in a few core situations. I will use before blocks if:
before { get :index }
). Even though you could use subject
for this in a lot of cases, it sometimes feels more explicit if you don't require a reference.If you find yourself writing large before
blocks for your specs, check your factories and make sure you fully understand traits and their flexibility.
before(:all) blocks
These are only ever executed once, before the specs in the current context (and its children). These can be used to great advantage if written correctly, as there are certain situations this can cut down on execution and effort.
One example (which would hardly affect execution time at all) is mocking out an ENV variable for a test, which you should only ever need to do once.
Hope that helps :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With