Retry code exists because real services fail intermittently, and that is exactly why testing it against a real service is a bad idea. A mock that walks a fixed sequence of responses, one per call, gives you a deterministic failure your suite can rely on, so you prove the retry actually happened instead of assuming it would the Quickmock retry guide. The same guide draws the line clearly: use a response sequence for unit tests, and reserve an error rate for soak tests where you deliberately want randomness.
This problem is not language-specific. A Stack Overflow question about testing a wrapper around a process that hangs states the goal precisely: define a list of scripted outcomes, run the wrapper, then assert both how many times the process was invoked and which outcome surfaced first the mockproc retry question. What you need is a way to count calls and to return a different value on each one. Every mocking library gives you both; the discipline is remembering to assert both.
There is a second reason to avoid live endpoints: retry bugs hide in the gaps between attempts. A client that retries but has no timeout will block on the first attempt and never reach the retry at all, which is the case most retry tests miss entirely the Quickmock retry guide. Fixed sequences let you test the count and the cause without waiting on anything real.
The decision rule
Use a fixed sequence when you are testing the wrapper's control flow: does it stop, does it count, does it preserve the error. Use randomized or fault-injection testing only when you are testing behavior under load, where the question is whether retries amplify an outage. Microsoft's architecture guidance is blunt about that second case: frequent client retries can prevent a service from recovering and worsen the problem, a pattern it calls a retry storm the Azure retry storm antipattern. The same page notes that retrying indefinitely is ineffective because requests typically remain valid only for a limited time.



