GuideBeginner
Test Doubles and Test Data
Learn to isolate the unit under test from its collaborators with test doubles (dummy, stub, spy, mock, fake), and to handle test data without drowning in setup. This guide continues the Reservo case right where the fundamentals guide left off: now booking and canceling touch the outside world through a `BookingService` that orchestrates four collaborators — a `Clock` for the time, a `PaymentGateway` to charge and refund, an `EmailSender` to confirm, and a `BookingRepository` to persist. That's exactly where doubles become necessary: you can't test against a real payment service on every run. You'll learn the precise vocabulary from Meszaros's taxonomy, how to stub what goes IN to the unit, how to verify with mocks and spies what comes OUT, how to build a fake that actually works, and how to spot "mock hell," where tests get coupled to implementation. It closes with the Builder pattern for test data that reads by intent, and a final project where you choose and justify the right double for each collaborator of the `BookingService`.
- 64
- lessons
- 8
- modules
- English · Spanish
- available in
- Yes
- certificate
- Free
- access
Outcomes
What you'll be able to do
- Distinguish the unit under test from its collaborators, and understand why you should NOT use a real service (slow, costly, non-deterministic) in a unit test
- Master the precise vocabulary of test doubles: dummy, stub, spy, mock, and fake (Meszaros's taxonomy), and distinguish state verification from behavior verification
- Write stubs that control what goes IN to the unit (canned responses) to test happy paths and failure paths, without over-specifying
- Write mocks and spies that verify what comes OUT of the unit (`unittest.mock`: `Mock`, `assert_called_once_with`, `call_args`), and recognize when that verification goes too far
- Build a fake that actually works (an in-memory repository) and understand the contract test that keeps it honest against the real implementation
- Recognize mock hell: tests coupled to implementation that break on every refactor, and the London vs. Detroit schools
- Use the Builder pattern and other test data tools (object mother, factories, sensible defaults) so a test reads by intent, not by setup noise
- Choose the right double for each collaborator in a real case (stub for queries, spy/mock for output effects, fake for persistence), and justify the choice
Before you start
What you need to bring
It's for you if...
- Devs who already completed testing fundamentals/TDD and now need to isolate units that depend on external collaborators (payments, email, persistence)
- Devs who overuse `unittest.mock` without judgment and end up with brittle suites that break on every refactor
- Teams that need readable test data instead of objects assembled by hand, line by line
- Devs who want to decide, with real judgment, when to double a collaborator and when to test it for real
Requirements and materials
- Testing Fundamentals and TDD guide completed (or equivalent: running pytest, the red-green-refactor cycle, asserts, basic fixtures, parametrize)
- Basic object-oriented Python knowledge (classes, constructor-based dependency injection)
- Python 3.14 and pytest 9.1.1 installed locally (`unittest.mock` is part of the standard library)
Content
The syllabus, module by module
Open any of them to see its lessons.
- 1. Module introduction: Reservo grows and collaborators appear
- 2. What is a collaborator
- 3. The problem with the real dependency
- 4. Side effects, non-determinism and cost
- 5. The seam and dependency injection
- 6. Testable code versus non-testable code
- 7. The fake clock, revisited
- 8. Mini-project: make `book` testable by injecting its collaborators
- 1. Module introduction: five doubles, five jobs
- 2. The dummy: a slot-filler that's never used
- 3. The stub: canned answers to control what comes in
- 4. The spy: records how it was called
- 5. The mock: expectations up front
- 6. The fake: a fake implementation that does work
- 7. State vs. behavior verification
- 8. Mini-project: name that double
- 1. Module introduction: the stub, controlling what comes in
- 2. What is a stub
- 3. Stubbing the clock
- 4. Stubbing a successful payment
- 5. Stubbing a failing payment
- 6. Stubs that return different answers according to the input
- 7. Don't overspecify the stub
- 8. Mini-project: test the two paths of `book` with stubs
- 1. Module introduction: verifying what goes out
- 2. Behavior verification: what goes out leaves no state
- 3. The hand-built spy
- 4. The `Mock` from `unittest.mock`
- 5. `assert_called_once_with` and `call_args`
- 6. Verifying the charge amount
- 7. Verifying that a call did NOT happen
- 8. Mini-project: verify the effects of `book`
- 1. Module introduction: the fake, an implementation that works
- 2. What is a fake
- 3. A `FakeBookingRepository` with a `dict`
- 4. A fake that really behaves: save and read
- 5. When the fake beats the stub or the mock
- 6. The danger: a fake can drift from the real one
- 7. The contract test that keeps the fake honest
- 8. Mini-project: write a fake and its contract test
- 1. Module introduction: the danger of overspecifying
- 2. What overspecifying is
- 3. The test that breaks on a refactor without changing behavior
- 4. Don't mock what you don't own
- 5. Don't mock value objects
- 6. London vs. Detroit
- 7. State by default, behavior in moderation
- 8. Mini-project: rescue a brittle mock-heavy suite
- 1. Capstone introduction: the process of choosing the double
- 2. Choose the double for each collaborator
- 3. `book`, happy path, with the mix
- 4. `book` with a declined payment
- 5. `cancel` with fake repo and fixed clock
- 6. Verify the effect without overspecifying
- 7. Use the builder for readability
- 8. Project: test `BookingService` with the right mix of doubles
Common questions
What people usually ask
No limit. It's a free guide: come in whenever you like, as often as you like.
No. Modules run from easier to harder, but you can jump to the one you need. Progress is saved per lesson.
Whatever is needed is listed under “What you need to bring”, above. If nothing is listed there, you can start from zero.
In the Club's WhatsApp group, and every two weeks there's a live with an instructor where questions get worked through.
Yes. It's issued automatically once you finish every lesson, with a verifiable code you can share on LinkedIn.
Start whenever you like
What students say
These reviews are from enrolled students who completed at least 50% of the course. We moderate reviews only on content grounds (spam, offensive language, personal data), never for being critical or negative.
No approved reviews yet.
Be the first to share your experience!