Problems Differentiating Rspec 'let' vs 'let!'

I read rspec docs and looked for several other places, but it’s hard for me to grasp the difference between rspec let and let!

I read that let not initialized until it is needed, and that its value is cached for example only. I also read that let! forces a variable into immediate existence and calls a call for each example. I think, since I am a beginner, it is difficult for me to understand how this relates to the following examples. Why :m1 must be installed using let! to claim that m1.content present on the page, but :user can be set with let to say that the page contains text: user.name ?

  subject { page } describe "profile page" do let(:user) { FactoryGirl.create(:user) } let!(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") } let!(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") } before { visit user_path(user) } it { should have_selector('h1', text: user.name) } it { should have_selector('title', text: user.name) } describe "microposts" do it { should have_content(m1.content) } it { should have_content(m2.content) } it { should have_content(user.microposts.count) } end end describe "after saving the user" do before { click_button submit } let(:user) { User.find_by_email(' user@example.com ') } it { should have_selector('title', text: user.name) } it { should have_success_message('Welcome') } it { should have_link('Sign out') } end 
+6
source share
2 answers

Since visit user_path(user) is called before the block, the user value is initialized there, and RSpec will visit this page. If :m1 :m2 did not use let! then the visit will not lead to the creation of content

 it { should have_content(m1.content) } it { should have_content(m2.content) } 

crash because it expects microposts to be generated before the user visits the page. let! allows you to create microcells before the called block is called, and when tests visit the page, microcells must already be created.

Another way to write the same tests and skip them, does the following:

 describe "profile page" do let(:user) { FactoryGirl.create(:user) } let(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") } let(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") } before do m1 m2 visit user_path(user) end 

calling the m1 and m2 variables before visit user_path(user) causes them to be initialized before the page is visited and causes the tests to pass.

UPDATE This small example makes sense:

In this example, we call get_all_posts, which returns an array of messages. Note that we call the method before the statement and before the it block is executed. Because the message is not called until the statement is executed.

 def get_all_posts Post.all end let(:post) { create(:post) } before { @response = get_all_posts } it 'gets all posts' do @response.should include(post) end 

using let! the post will be created as soon as RSpec sees the method (before the before block), and the message will return to the Post list

Again, another way to do the same would be to call the variable name in front of the block before we call the method

 before do post @response = get_all_posts end 

since this ensures that the let(:post) block is called before the method that creates Post is called, so that it returns to the Post.all call

+12
source

The key to differentiation is how rspec performs the steps.

Look at the code again:

 let(:user) { FactoryGirl.create(:user) } let!(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") } let!(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") } before { visit user_path(user) } 

If we use let instead of let !, m1 and m2 are not created at the moment. Then Rspec makes a visit and the page loads, but obviously the page does not have m1 or m2.

So now, if we call m1 and m2, they will be created in memory. But it is already too late, since the page will not be loaded again if we do not intentionally do this. Therefore, any UI test on the page will fail.

0
source

Source: https://habr.com/ru/post/948483/


All Articles