01 — Deterministic Unit Testing, AAA & Fixtures

At a glance

After completing this lesson you can:

Time: ~45 minutes · Prerequisites: 04 — Context Managers & Exceptions

Reading Companion

Why this matters in production

A flaky test suite that fails 2% of the time in CI is worse than no test suite at all: developers start ignoring CI red lights, and real regressions slip into production. True unit tests must be 100% deterministic, running in milliseconds without relying on time.sleep(), live databases, or network calls.

Deep dive

1. The AAA Pattern

Hands on

python3 phase0-foundations/04-testing-and-verification/01-unit-testing-and-fixtures/examples/01_demo.py
python3 phase0-foundations/04-testing-and-verification/01-unit-testing-and-fixtures/examples/02_trap.py

AI Trap & Code Review

# BAD AI-GENERATED CODE — FLAKY TIME DEPENDENCY
import time

def test_cache_expiration():
    cache.set("key", "val", ttl_seconds=1)
    time.sleep(1.05)  # Flaky! If CI runner lags, test fails or wastes 1 second per test!
    assert cache.get("key") is None

Exercises

  1. Rung 1 (parse_duration_seconds): Convert string durations ("10s", "5m", "2h", "1d") into total integer seconds.
  2. Rung 2 (TtlCache — Fix the AI Bug): Fix an in-memory TTL cache that used time.time() directly by injecting a clock_fn: Callable[[], float] for deterministic testing.
  3. Rung 3 (Parameterized Validator): Implement an email format validator with comprehensive boundary assertions.
  4. Rung 4 (InMemoryEventBus): Build an event bus supporting subscribe and publish with isolated subscriber failure handling.
  5. Rung 5 (DeterministicIdGenerator): Create an ID generator accepting a seeded PRNG for reproducible test runs.

Wrapping up

Can you explain?

  1. Why is time.sleep() in unit tests a severe anti-pattern?
  2. What makes a test truly a "unit" test versus an "integration" test?
  3. What is the Arrange-Act-Assert pattern?

Further Reading & References

Show reference solution notes

Solution & Engineering Notes — 01 Unit Testing & Fixtures

  1. Clock injection: Passing clock_fn: Callable[[], float] allows unit tests to freeze or fast-forward time instantly (clock = 100.0, then clock = 105.0) with zero real-world delays.
  2. Deterministic IDs: Injecting sequence or PRNG generators ensures snapshots and assertion comparisons remain identical across every single test run.

Self-check

Run python3 -m unittest phase0-foundations/04-testing-and-verification/01-unit-testing-and-fixtures/test_exercises.py -v until green, then record it here. Saved to progress/rungs.json; commit it.

Confidence:

Completion edits PROGRESS.md; commit it with the lesson.