People seem to have explained some of the basic ways in which they differ, but are not accounted for before (: all) and do not explain why they should be used.
I believe that instance variables do not have a place in the vast majority of specifications, partly because of the reasons mentioned in this answer , so I will not mention them as an option here.
let blocks
The code inside the let block is executed only if there is a link, lazy loading means that the ordering of these blocks does not matter. This gives you more power to reduce re-tuning through your specifications.
One (extremely contrived and small) example:
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 is no need to repeat the definition of subject . It is important to note that the last let block defined in the current context will be used. This is useful for setting the default for most specifications, which can be overwritten if necessary.
For example, checking the return value of calculate_awesome , if the person model with top_hat , is set to true, but the mustache will not:
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 worth noting about let blocks is that they should not be used if you are looking for something that has been stored in the database (i.e. Library.find_awesome_people(search_criteria) ) since they will not be stored in the database if they were no longer links. let! Blocks or before should be used here.
Also, never ever use before to start let blocks execute, this is what let! made for!
let be! blocks
let! blocks are executed in the order in which they are defined (as before the block). One major difference before blocks is that you get an explicit reference to this variable, instead of having to return to instance variables.
As with let blocks, if multiple let! Blocks defined with the same name, the very last one is what will be used during execution. The main difference is that let! Blocks will be executed several times if they are used like this, whereas the let block will execute only the last time.
before (: each) blocks
before(:each) is the default value before the block, so you can call it before {} instead of specifying the full before(:each) {} every time.
I prefer using before blocks in several basic situations. I will use up blocks if:
- I use mockery, stubbing or doubleles
- There is some kind of reasonable size setting (usually this is a sign that your factory features are set incorrectly).
- There are a number of variables that I do not need to refer directly to, but are required for installation
- I am writing functional controller tests in rails and I want to execute a specific request for testing (ie
before { get :index } ). Even if you can use subject for this in many cases, sometimes it becomes more explicit if you don't need a link.
If you find yourself writing large before blocks for your specifications, check your plants and make sure you fully understand the features and their flexibility.
to (: all) blocks
They are executed only once, before the specifications in the current context (and its children). They can be used with great advantage if they are written correctly, as there are certain situations that can shorten the execution and effort.
One example (which is unlikely to affect run time at all) is making fun of the ENV variable for a test that you only ever need to do.
Hope that helps :)