Question 4
Maintaining a healthy test suite
As a codebase grows, test suites often become slow and brittle. How do you keep tests fast, reliable, and valuable over time?
Follow-ups
- How do you handle flaky tests in CI?
Answer outline
A healthy suite follows the test pyramid: many fast unit tests at the base, fewer integration tests in the middle, and a small number of UI tests at the top. Treat it like product code — name tests after behavior, delete duplicates, and refactor helpers when setup balloons.
A small factory keeps model construction in one place with sensible defaults — each test only passes the fields that matter for the scenario:
struct User: Equatable {
let id: String
let name: String
let email: String
}
enum UserFactory {
static func make(
id: String = "u1",
name: String = "Ada Lovelace",
email: String = "ada@example.com"
) -> User {
User(id: id, name: name, email: email)
}
}
// Examples: override just what you assert on
let guest = UserFactory.make(id: "guest-42")
let verified = UserFactory.make(name: "Grace Hopper", email: "grace@example.org")
Slow suites almost always trace to too much I/O, global state, or test data that's far larger than the test needs. Partition by speed — fast unit tests on every push, integration in a separate job, UI and device tests nightly — and parallelize safely by isolating derived data and temp directories per worker.
Brittleness often comes from relying on live backend data — real servers change, go down, or return different responses, making tests fail for reasons unrelated to your code. Stub or fake external dependencies so tests assert your logic, not the state of a backend.
Principles
- Track test duration per target and fail CI builds that regress beyond budget.
- Quarantine flaky tests — reproduce, fix root cause, or delete; don’t skip them indefinitely.
- Use shared factories to construct test data — one place, sensible defaults, no duplicated setup.
- No real networking in unit tests — use stubs; maintain record/replay only if it stays current.
- Write tests that read like bug reports — a clear name and focused assertion beats a clever abstraction.