Module 4 – Reservation & Ranking Services
Purpose
This short report explains what I built for the Module 4 assignment and, more importantly,
teaches the essentials of test doubles and seams in a practical, developer-friendly way.
You should be able to understand why deterministic tests matter, what a seam is, and how a
mocking framework (Mockito) enables us to inject a test double in place of a real
dependency.
What is a Test Double?
A test double is a controllable stand-in for a real dependency used during testing. Common
types include:
• Dummy – passed around but never used.
• Stub – returns fixed data to the system under test.
• Fake – has a working but simplified implementation (often deterministic).
• Mock – behavior is specified/verified within the test (often via frameworks like Mockito).
• Spy – records calls so tests can later assert how it was used.
Why use them? Real dependencies can be slow, flaky, hard to set up, or non-deterministic
(e.g., random numbers). Test doubles make tests fast, repeatable, and expressive.
What is a Seam?
A seam is a place in the code where you can change behavior without editing production
source.
Examples:
• Compiler / In-code seam (e.g., an if(testMode) …)
• Linker / Classpath seam (swap an implementation on the classpath)
• Dependency Injection seam (pass dependencies via constructor/parameters)
• Mocking framework seam (use a tool to substitute behaviors in tests)
In this project I used a mocking framework seam (Mockito) together with constructor
injection.
The production class (ReservationService) accepts a RankingService interface in its
constructor, so tests can supply either a real implementation, a deterministic fake, or a
Mockito mock.
System Overview
The application has three main parts:
• ReservationService – the class under test. It makes a reservation decision based on a
customer’s rank.
• RankingService – an interface providing a rank in [0..100].
– RandomRankingService (real): stochastic; returns a random rank each call.
– FakeRankingService (test double): deterministic; returns configured values so tests are
stable.
Reservation Rules (default thresholds):
• rank ≥ 80 → CONFIRMED
• 50 ≤ rank < 80 → WAITLISTED
• rank < 50 → REJECTED
Seam Used (Mockito + Constructor Injection)
I made ReservationService depend on the RankingService interface and receive it through
the constructor.
In tests, I exploit this seam to insert a test double:
• Mockito mock: mock([Link]) and when(getRank(...)).thenReturn(...)
• Deterministic fake: new FakeRankingService(map, defaultRank)
This guarantees deterministic ranks for specific customers (e.g., Alice=95, Bob=65, Eve=42),
so expected outcomes are fully predictable.
Why the Real Service Causes Flaky Tests
The real RandomRankingService returns a random rank on every call. That randomness
means an assertion like
“Alice must be CONFIRMED” may pass on one run and fail on another. Flaky tests destroy
trust in CI and slow teams down.
A test double removes randomness and restores determinism.
How the Tests Demonstrate the Seam
1) Deterministic tests (Mockito and Fake)
• Arrange: inject a mock or fake with controlled ranks.
• Act: call reserve(customer).
• Assert: outcomes are CONFIRMED/WAITLISTED/REJECTED exactly as expected.
• Result: Pass consistently.
2) Flaky test (Real random service)
• Arrange: inject new RandomRankingService().
• Act/Assert: test expects CONFIRMED for Alice.
• Result: Intermittent failure by design, showing why the seam is necessary.