Bird
Raised Fist0
Rubyprogramming~10 mins

Test doubles concept in Ruby - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Test doubles concept
Start Test
↓
Create Test Double
↓
Define Expected Calls
↓
Run Code Using Double
↓
Verify Calls
↓
Pass or Fail Test
↓
End
The test creates a double, sets expected calls, runs code using it, then verifies if calls match expectations.
Execution Sample
Ruby
double = double('User')
allow(double).to receive(:name).and_return('Alice')
puts double.name
expect(double).to have_received(:name)
This code creates a test double for 'User', sets it to return 'Alice' when name is called, prints the name, and checks if name was called.
Execution Table
StepActionEvaluationResult
1Create double 'User'double createddouble object ready
2Stub method :name to return 'Alice'method :name stubbeddouble.name returns 'Alice'
3Call double.namedouble.name called'Alice' returned and printed
4Verify double received :name callcheck call historycall found, verification passes
5Test endsall expectations mettest passes
💡 Test ends after verifying all expected calls were made successfully.
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
doublenildouble objectdouble with :name stubdouble with :name calleddouble with call verified
Key Moments - 3 Insights
Why do we create a test double instead of using the real object?
We create a test double to isolate the test from real object behavior and dependencies, as shown in step 1 of the execution_table.
How does the test know if the double's method was called?
The test tracks method calls on the double internally, verified in step 4 where it checks the call history.
What happens if the expected method is not called on the double?
The verification in step 4 would fail, causing the test to fail because the expected call was missing.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the result after step 3 when double.name is called?
AMethod :name stubbed
B'Alice' returned and printed
CCall found, verification passes
DDouble object ready
💡 Hint
Check the 'Result' column in row for step 3 in execution_table.
At which step does the test verify if the double received the expected method call?
AStep 2
BStep 1
CStep 4
DStep 3
💡 Hint
Look at the 'Action' column in execution_table to find when verification happens.
If we did not stub the method :name to return 'Alice', what would happen at step 3?
AThe call would return nil or error
B'Alice' would still be returned
CVerification would pass automatically
DDouble would not be created
💡 Hint
Refer to step 2 and 3 in execution_table about stubbing and method call results.
Concept Snapshot
Test doubles are fake objects used in tests to stand in for real ones.
Create a double, stub methods to return expected values.
Run code using the double, then verify expected calls happened.
This isolates tests and controls behavior for reliable testing.
Full Transcript
This visual execution shows how test doubles work in Ruby. First, a double object is created to represent a real object. Then, we stub a method on the double to return a fixed value. When the method is called, it returns the stubbed value. The test then verifies that the method was called on the double. If all expected calls happen, the test passes. This helps test code in isolation without relying on real objects.

Practice

(1/5)
1.

What is the main purpose of using test doubles in Ruby testing?

easy
A. To permanently change the behavior of classes
B. To speed up the program execution in production
C. To replace real objects with fake ones to isolate tests
D. To automatically generate user interface elements

Solution

  1. Step 1: Understand what test doubles do

    Test doubles are fake objects used in tests to replace real parts of the program.
  2. Step 2: Identify the main goal

    The goal is to isolate the part being tested by removing outside effects from real objects.
  3. Final Answer:

    To replace real objects with fake ones to isolate tests -> Option C
  4. Quick Check:

    Test doubles isolate tests = A [OK]
Hint: Test doubles fake objects to isolate tests quickly [OK]
Common Mistakes:
  • Thinking test doubles speed up production code
  • Believing test doubles permanently change classes
  • Confusing test doubles with UI tools
2.

Which of the following is the correct way to create a test double named user in Ruby using RSpec?

?
easy
A. user = fake('user')
B. user = double('user')
C. user = stub('user')
D. user = mock_object('user')

Solution

  1. Step 1: Recall RSpec syntax for test doubles

    RSpec uses the method double to create test doubles.
  2. Step 2: Match the correct method call

    The correct syntax is double('name'), so double('user') is right.
  3. Final Answer:

    user = double('user') -> Option B
  4. Quick Check:

    RSpec double creation = A [OK]
Hint: Use double('name') to create test doubles in RSpec [OK]
Common Mistakes:
  • Using fake or stub instead of double
  • Confusing mock_object with double
  • Missing quotes around the name
3.

What will be the output of this Ruby code using a test double?

user = double('user')
allow(user).to receive(:name).and_return('Alice')
puts user.name
medium
A. Alice
B. nil
C. user
D. NoMethodError

Solution

  1. Step 1: Understand the double setup

    The double user is told to respond to name with 'Alice'.
  2. Step 2: Check the method call output

    Calling user.name returns 'Alice' as set by and_return.
  3. Final Answer:

    Alice -> Option A
  4. Quick Check:

    Double returns stubbed value = C [OK]
Hint: Stub method with and_return to control output [OK]
Common Mistakes:
  • Expecting the double name instead of stubbed return
  • Thinking it returns nil by default
  • Assuming NoMethodError without stub
4.

Identify the error in this test double usage and how to fix it:

order = double('order')
allow(order).to receive(:total)
puts order.total
medium
A. Missing and_return causes order.total to return nil, fix by adding and_return
B. Double name should be a symbol, fix by using double(:order)
C. Cannot call allow on a double, fix by using expect
D. Missing puts before order.total

Solution

  1. Step 1: Analyze the stub setup

    The method total is allowed but no return value is set, so it returns nil.
  2. Step 2: Fix by adding return value

    Add and_return(value) to specify what total should return.
  3. Final Answer:

    Missing and_return causes order.total to return nil, fix by adding and_return -> Option A
  4. Quick Check:

    Stub needs return value = B [OK]
Hint: Always add and_return to stub methods for expected output [OK]
Common Mistakes:
  • Thinking double name must be symbol
  • Confusing allow with expect usage
  • Forgetting to print output
5.

You want to test a PaymentProcessor class that calls an external Gateway service. How can you use a test double to ensure your test does not call the real Gateway?

class PaymentProcessor
  def initialize(gateway)
    @gateway = gateway
  end

  def pay(amount)
    @gateway.charge(amount)
  end
end

# Test code here?
hard
A. Remove the gateway parameter and hardcode the call inside PaymentProcessor
B. Call the real Gateway class directly in the test
C. Use allow_any_instance_of(Gateway) to stub charge
D. Create a double for gateway that expects charge with amount and returns true

Solution

  1. Step 1: Understand dependency injection

    The PaymentProcessor takes a gateway object to call charge.
  2. Step 2: Use a test double for gateway

    Create a double that expects charge with the amount and returns true to simulate success.
  3. Step 3: Avoid calling real external service

    This prevents the test from calling the real Gateway, isolating the test.
  4. Final Answer:

    Create a double for gateway that expects charge with amount and returns true -> Option D
  5. Quick Check:

    Use doubles to isolate external calls = D [OK]
Hint: Inject doubles to replace external services in tests [OK]
Common Mistakes:
  • Calling real external services in tests
  • Hardcoding dependencies inside classes
  • Using allow_any_instance_of unnecessarily
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