Bird
Raised Fist0
Rubyprogramming~10 mins

Let and before hooks in Ruby - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Let and before hooks
Define let variable
↓
Run before hook
↓
Execute test example
↓
Use let variable (lazy evaluated)
↓
Test completes
This flow shows how a let variable is defined lazily, before hooks run setup code, and then the test example uses the let variable.
Execution Sample
Ruby
let(:number) { 5 }

before do
  @result = number * 2
end

it "doubles the number" do
  expect(@result).to eq(10)
end
This code defines a let variable 'number', runs a before hook to set @result, then tests that @result equals 10.
Execution Table
StepActionEvaluationResult
1Define let(:number)No evaluation yetnumber is ready but not called
2Run before hookCalls number for first timenumber evaluated to 5, @result set to 10
3Run test exampleUse @result@result is 10, test passes
4Test endsNo more codeTest complete
💡 Test ends after example runs and assertions pass
Variable Tracker
VariableStartAfter before hookAfter test exampleFinal
number (let)not evaluatedevaluated to 5evaluated to 5evaluated to 5
@resultnil101010
Key Moments - 3 Insights
Why is the let variable 'number' not evaluated when defined?
Because let variables are lazy; they only run when first called, as shown in step 2 of the execution_table.
When does the before hook run in relation to the test example?
The before hook runs before the test example, setting up variables like @result, as seen in step 2 before step 3.
Can the let variable be used inside the before hook?
Yes, the let variable is evaluated the first time it is called, even inside the before hook, as step 2 shows.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, at which step is the let variable 'number' first evaluated?
AStep 2
BStep 1
CStep 3
DStep 4
💡 Hint
Check the 'Evaluation' column in execution_table rows for when 'number' is evaluated.
According to variable_tracker, what is the value of @result after the before hook runs?
A5
B10
Cnil
Dundefined
💡 Hint
Look at the '@result' row under 'After before hook' column in variable_tracker.
If the before hook did not call 'number', when would 'number' be evaluated?
ANever
BAt test definition time
CWhen the test example calls it
DBefore the before hook
💡 Hint
Recall that let variables are lazy and only evaluated when first used, as shown in the flow and execution_table.
Concept Snapshot
let(:name) { value } defines a lazy variable.
before hooks run setup code before each test.
let variables are evaluated only when first called.
before hooks can use let variables, triggering evaluation.
Test examples use variables set up by before hooks and let.
This helps organize test setup cleanly and efficiently.
Full Transcript
This visual execution trace shows how Ruby's let and before hooks work in tests. First, a let variable 'number' is defined but not evaluated immediately. Then, the before hook runs, calling 'number' for the first time, which evaluates it to 5 and sets @result to 10. Next, the test example runs, using @result which is 10, so the test passes. The variable tracker shows 'number' changes from not evaluated to 5 after the before hook, and @result changes from nil to 10. Key moments clarify that let variables are lazy and evaluated only when called, including inside before hooks. The quizzes check understanding of when evaluation happens and variable values. The snapshot summarizes that let defines lazy variables, before hooks run setup before tests, and together they organize test code cleanly.

Practice

(1/5)
1. What is the main purpose of using let in Ruby tests?
easy
A. To create reusable values that are lazily evaluated
B. To run setup code before each test
C. To define a test case
D. To clean up after tests run

Solution

  1. Step 1: Understand let behavior

    let defines a value that is created only when needed (lazy evaluation) and reused within the same test.
  2. Step 2: Differentiate from before

    before runs code before each test but does not create reusable values like let.
  3. Final Answer:

    To create reusable values that are lazily evaluated -> Option A
  4. Quick Check:

    let = reusable lazy value [OK]
Hint: Remember: let creates values, before runs code [OK]
Common Mistakes:
  • Confusing let with before hook
  • Thinking let runs before each test eagerly
  • Assuming let defines test cases
2. Which of the following is the correct syntax to define a let variable named user with value "Alice"?
easy
A. before { user = "Alice" }
B. let user = "Alice"
C. let(:user) { "Alice" }
D. let user { "Alice" }

Solution

  1. Step 1: Recall let syntax

    let takes a symbol argument and a block returning the value: let(:name) { value }.
  2. Step 2: Check each option

    let(:user) { "Alice" } matches correct syntax. Options B and D miss parentheses or block syntax. before { user = "Alice" } uses before, not let.
  3. Final Answer:

    let(:user) { "Alice" } -> Option C
  4. Quick Check:

    Correct let syntax uses symbol and block [OK]
Hint: Use parentheses and block for let: let(:name) { value } [OK]
Common Mistakes:
  • Omitting parentheses around symbol
  • Using assignment instead of block
  • Confusing let with before syntax
3. Given the code below, what will be printed when the test runs?
let(:count) { 0 }
before { count += 1 }
it "increments count" do
  puts count
end
medium
A. 0
B. 1
C. 2
D. Error: undefined method += for nil

Solution

  1. Step 1: Understand let and before interaction

    let(:count) { 0 } defines a method returning 0. But count is not a variable; it's a method call.
  2. Step 2: Analyze before { count += 1 }

    count += 1 tries to modify count as a variable, but count is a method, so Ruby raises an error: undefined method += for nil or no local variable.
  3. Final Answer:

    Error: undefined method += for nil -> Option D
  4. Quick Check:

    Cannot modify let method return with += [OK]
Hint: let defines methods, not variables; += fails on method calls [OK]
Common Mistakes:
  • Assuming let creates a variable to modify
  • Expecting count to increment automatically
  • Ignoring that let is lazily evaluated method
4. Identify the error in the following test setup:
let(:numbers) { [1, 2, 3] }
before do
  numbers << 4
end
it "checks numbers length" do
  expect(numbers.length).to eq(4)
end
medium
A. Modifying let value causes shared state between tests
B. No error; test passes as expected
C. Syntax error in let definition
D. before block runs after the test

Solution

  1. Step 1: Understand let and before execution order

    let(:numbers) memoizes a new array [1,2,3] the first time numbers is called in each test example.
  2. Step 2: Trace the test execution

    In before, numbers << 4 calls/memoizes numbers and mutates it to [1,2,3,4]. In it, numbers.length (memoized) is 4, so test passes.
  3. Final Answer:

    No error; test passes as expected -> Option B
  4. Quick Check:

    Mutation in before(:each) affects per-example memoized let correctly [OK]
Hint: let memoizes per example; before mutation visible consistently in test [OK]
Common Mistakes:
  • Misunderstanding per-example memoization (no inter-test sharing)
  • Thinking mutation always causes shared state between tests
  • Confusing before(:each) with before(:all)
5. You want to test a user object that requires setup before each test and a reusable user name. Which is the best way to combine let and before hooks?
let(:user_name) { "Bob" }
before do
  @user = User.new(name: user_name)
  @user.activate!
end
it "checks user is active" do
  expect(@user.active?).to be true
end

What is the main advantage of this approach?
hard
A. Separates reusable data (user_name) from setup actions (before)
B. Runs let block after before hook
C. Avoids using instance variables for test data
D. Ensures user_name is reset after each test

Solution

  1. Step 1: Analyze separation of concerns

    let(:user_name) defines reusable data lazily, while before runs setup code creating and activating user.
  2. Step 2: Understand benefits

    This keeps data definition and setup logic cleanly separated, improving test readability and maintainability.
  3. Final Answer:

    Separates reusable data (user_name) from setup actions (before) -> Option A
  4. Quick Check:

    let for data, before for setup [OK]
Hint: Use let for data, before for setup steps [OK]
Common Mistakes:
  • Thinking let runs before before hook
  • Avoiding instance variables unnecessarily
  • Confusing reset behavior of let
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard