What makes code untestable — time, randomness, singletons, UserDefaults — and how to introduce seams?
The gist
Code is untestable when it reaches out to the global world on its own: Date(), Int.random, UUID(), UserDefaults.standard, Analytics.shared, Task.sleep. A test cannot intercept such calls, and the result depends on the clock, luck and whatever previous tests left behind. The cure is seams (Michael Feathers' term) — places where behaviour can be replaced without editing the logic itself. In Swift the cheapest seam is an init parameter with a default value: production code stays the same, and the test passes its own value.
The rest of this answer, with code and interview follow-ups, is in the DevPrep app.
Read the full answer in DevPrep