A testable network layer

Networking Mid-level Swift 5.5+ iOS 15+ Reviewed By Alok Singh

Pick the fix

How do you unit-test a view model that loads data without hitting the network?

Options
Hint 1 of 1

Where is the seam?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Inject an HTTPClient protocol and pass a stub that returns canned data in tests

Correct. Tests are fast, deterministic and offline.

Why not the others?
  • B Call a staging server from the unit tests. Tests become slow and flaky, and fail when staging is down.
  • C Swizzle URLSession methods at runtime. It's fragile and relies on Objective-C runtime hacks.
  • D Add a static isTesting flag to a network singleton. Production code fills up with test branches.

30-second answer

Hide URLSession behind a small protocol, for example protocol HTTPClient { func data(for: URLRequest) async throws -> (Data, URLResponse) }. Inject it into services and view models. In production pass URLSession; in tests pass a stub that returns canned responses or errors, so tests are fast, deterministic and offline.

Practise saying it · 45 s. No recording, just a timer

Explain how you make networking testable.

Say your answer out loud, then check which of these points you covered:

  • Small protocol seam
  • Inject it
  • Stubs in tests

Deep dive

Describe endpoints as values (path, method, query, body) built in one place.

A URLProtocol subclass can stub the session itself for integration-style tests.

Keep decoding and error mapping in the service, not the view model.

Make the client Sendable for use across concurrency domains.

Common mistakes

  • Calling real servers from unit tests.
  • Global singletons that tests can't replace.

Senior take & follow-ups

Seniors keep the seam small and inject it everywhere.

Follow-up questions

Think of your answer first, then open the hint.

  1. Protocol stub or URLProtocol?

    Show hint

    Stub for unit tests; URLProtocol to test request building end to end.

  2. Where do auth headers go?

    Show hint

    One decorator or the client, not every call site.

Suggest a fix if something here is wrong or out of date.