In RSpec, there are two different ways to write DRY tests, by using or . Their purpose is to create variables that are common across tests. In this post, we will explore differences between before and let and explain . before let why let is preferred by the Ruby community let Let creates lazily-evaluated local variables. This means that let() is not evaluated until the method that it defines is run for the first time. It DRYs up the spec and makes it more readable. $count = describe let( ) { $count += } it expect(count).to eq( ) expect(count).to eq( ) it expect(count).to eq( ) 0 "let" do :count 1 "stores the value" do 1 1 end "is not cached across examples" do 2 end end Let should not be used for local variables, which have to be saved to the database, as they will not be saved to the database unless they have already been referenced. In this case, you should use or . let! before blocks The the tests we are creating are done using . RSpec and Capybara Also, have a let block inside of a before the block, this is what let! is made for! never let! Unlike let, you can . It means that, even if you didn't invoke the helper method inside the example, it will be invoked before your example runs. use let! to force the method's invocation before each example $count = describe invocation_order = [] let!( ) invocation_order << $count += it invocation_order << expect(invocation_order).to eq([ , ]) expect(count).to eq( ) 0 "let!" do :count do :let! 1 end "calls the helper method in a before hook" do :example :let! :example 1 end end As with let blocks, if multiple let! blocks are defined with the same name, the most recent one will be executed. The core difference is that will be executed multiple times if used like this, whereas the will only execute the last time. let! blocks let block before(:each) Before(:each) block will run before each example, even if the example doesn't use any of the instance variables defined in the block. This can noticeably slow down the setup of the instance variables. @tests = [] describe User before( ) @user = User.new describe it @user.should have( ).tests it @user.tests << Object.new it @user.should have( ).tests class User def tests || end end do :each do end "initialized in before(:each)" do "has 0 tests" do 0 end "can accept new tests" do end "does not share state across examples" do 0 end end end Depending on your personal preference you could use before blocks when: In nearly every situation, it is better to use let over before blocks. There is a reasonable amount of variables. There are variables that don't need to be referenced directly but are required. There are many commands to be executed because its syntax is more clear when many commands are involved. Creating mocks/stubs. Give it a try and create your own model or ! controller tests before(:all) This block is executed only once, before all of the examples in a group. There are certain situations this can cut down on execution and effort. @tests = [] describe User before( ) @user = User.new describe it @user.should have( ).tests it @user.tests << Object.new it @user.should have( ).tests class User def tests || end end do :all do end "initialized in before(:all)" do "has 0 tests" do 0 end "can get accept new tests" do end "shares state across examples" do 1 end end end It runs outside of transactions, so the data created here will bleed into other specs. Using before(:all) in RSpec will cause you lots of trouble unless you know what you are doing! Conclusion It all depends on what and how you need to make the work or consider using for creating data. Let blocks bring more to the table than before blocks. RSpec tests FactoryGirl Besides being slower, one of the major problems with before blocks is that spelling errors can lead to bugs and false positives, allowing certain types of tests to pass when they shouldn't. before( ) @user = User.find( ) @user.logout it expect(@usr).to be_nil :each do username: "kolosek" end "should log the user out" do end Since @usr wasn't previously defined, the test will pass, @usr is nil by default. The same test using let would raise NameError because @usr isn't defined. Hope this will help you to better understand the differences between let and before blocks. Thank you for reading! Previously published at https://kolosek.com/rspec-let-vs-before/