CodeRigor

FREE LESSON

Testing seams & injected dependencies

Pure functions, fake clocks and retry policies with visible failures and precise interaction tests.

A useful test distinguishes correct behavior from a plausible failure. Test boundaries and invariants, then deliberately introduce a defect and ensure the test fails. Avoid checking only that a function returned something.

Inspect the fake sleeper rather than waiting for real time to pass.

Three attempts, two waits
start / 3
Timeouts before another allowed attempt produce exponential waits. The final successful call returns without another sleep.
Three attempts, two waits
Timeouts before another allowed attempt produce exponential waits. The final successful call returns without another sleep.
Python
import unittest


class Contract(unittest.TestCase):
    def runTest(self):
        self.assertEqual(sum([1, 2, 3]), 6)
        with self.assertRaises(ValueError):
            int("bad")


result = unittest.TestResult()
Contract().run(result)
print(result.wasSuccessful())

Inject effects as arguments: a clock, sleeper, random generator or request adapter. A fake can record calls and deterministically return or raise. This makes failure paths testable without a server, network, API key or actual wait.

Python
waits = []


def backoff(attempt, sleep):
    sleep(0.1 * 2**attempt)


backoff(2, waits.append)
print(waits)  # [0.4]

The build retries only TimeoutError. attempts counts total calls, including the initial call. After the last failure, raise that error and do not sleep. Nonretryable exceptions propagate immediately. Retrying every exception can conceal a programming error; sleeping after a terminal failure wastes time.

Use separate failure cases to test retry exhaustion and nonretryable exceptions.

Different failure policies
A timeout may retry within budget. A ValueError is not retried. An exhausted timeout budget also propagates without another wait.
Different failure policies
A timeout may retry within budget. A ValueError is not retried. An exhausted timeout budget also propagates without another wait.

Assert the returned value, adapter call count, sleep sequence and final error. A successful None is still a successful result. The sleeper is synchronous here; a later skill introduces async concurrency and cancellation. These are local policy exercises, not production API availability guarantees.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Focus on test cases, assertions and mocks. The retry exercise uses injected work and sleep functions so tests can check attempts and backoff without real I/O or waiting.