0

When can I use let or let! and how can I then refer to variables inside the test?

How does the usage of let and let! compare to using before :each and before :all?

Michael Durrant
  • 93,410
  • 97
  • 333
  • 497

1 Answers1

0

The 'classic' way of using before(:each) and before(:all) is

describe "tests" do
  before :each do
    @var1='a'
    @var2='b'
  end
end

You then refer to the instance variables by preceeding them with an @ sign inside the tests, i.e.

describe "tests" do
  before :each do
    @var1='a'
    @var2='b'
  end
  it  "does stuff" do
    a=some_class.some_method(@var1)
    expect(a).to eq @var2
  end
end

If you want a variable to have the same value in each test you can use before :all.
If you want a variable to have the same value generated for each test use before :each.
Generally use before :each as improper use of before :all can too easily lead to intermittent test failures.
Think of before :all as defining constants.

The let/let! format looks like this:

describe "tests" do
  let(:var1)  {'a'}
  let!(:var2) {srand(25)}
  it  "does stuff" do
    a=some_class.some_method(var1)
    expect(a).to eq var2
  end
end

Notice several things:

  1. var1 and var2 now look like local variables, i.e. var1 instead of @var1 when used in the test and setup. In actual fact they are test class methods. The important thing to note for usage is that you do NOT use the @ sign when subsequently using them unlike the before :each and before :all where you did.
  2. In the first case of the let's example, let is used with var1. This allow the memoization across examples to work. In the second case let! is used with var2. This is needed because you want the variable (method) to be called/set explicitly before each use. srand() is a great example of when you would need this as it seeds the random number generator but only for the next use of rand() so if using it in multiple test examples resetting it is needed each time.
Michael Durrant
  • 93,410
  • 97
  • 333
  • 497
  • 1
    Just adding my two cents. I prefer to leave the `:each` out of my normal `before` statements. It just looks cleaner. Then add `:all` on the off chance that I make a `before(:all)` block. Another interesting find was you could mimic the `let` paradigm in `subject` lines, essentially namespacing nested subjects `subject(:call_some_method) { some_class.some_method(var1) }` so then the `it` block is a single line, and reads very well. – Brad Rice Apr 13 '14 at 21:33
  • Both `let` and `let!` get re-evaluated every time, so your random number will be different each time irrespective of which one you use. The difference is when they are initialised. `let!` is initialised before all examples - even examples which don't use it. `let` is initialised the first time an example uses it. – Hakanai Nov 18 '14 at 05:52