TT Lab
Get started
Learn Learning paths Courses

Testing Tools in Practice

Design principles: Test failure paths and side effects in isolation

Continue in TT Lab

Summary

In a failure test, observe not only the final return value but also the call count, the waiting, and the file state.

Why this matters

A briefly dropped connection can be recovered by a retry, but invalid input is not fixed by repeating the same request. If you lump both errors together with except Exception, even when a success response comes back you get hidden duplicate calls and needless waiting. You must be able to exercise the failure paths without really cutting an external server or waiting several seconds at a time, so that developers run the tests every time.

How it works

fetch(send, sleep, cache) calls the send it is given and retries only on TimeoutError. There are at most 3 calls in total, and it passes 0.1 seconds after the first failure and 0.2 seconds after the second failure to sleep. On the third failure it raises the exception without waiting any longer. A permanent error such as ValueError propagates immediately. A successful string is saved as UTF-8 to cache, which is a pathlib.Path, and then returned. Even if the saving itself fails, the error is not hidden.

성공 → 파일 저장 → 반환
시간 초과 → 시도 남음? → 대기 → 재호출
           └─ 없음 → 예외, 기존 파일 그대로
영구 오류 → 즉시 예외

What it looks like in the field

A fake send keeps a record of its calls in a list and returns errors and values in a fixed order. A fake sleep only records the delay values. tmp_path provides a different directory for every test, so the cache of a previous test cannot make the next test pass. The contract of preserving an existing cache concerns network failures. A plain write_text does not protect atomically even against a disk failure in the middle of writing, so we do not call this implementation an atomic file replacement.

What you will do in the next lab

You verify success, recovery after a transient failure, exhaustion, a permanent error, the sequence of waits, saving on success, preservation on failure, and a save error, each in turn. In a root environment, you must not assume that chmod alone can make a write fail. Choose a failure condition that depends less on the environment, such as making it write file contents to a directory. Grading runs the same tests against the correct and defective implementations, and you do not pass with the wording of a report or just a declaration of mock calls.

See also: pytest tmp_path