How to test without mocking
Mocking in software tests is challenged as an alleged anti-pattern, with critics arguing that mocks often only cover “happy paths,” drift from real behavior, and hide bugs that surface when talking to real databases or external services. Many engineers counter that mocks are valuable for fast, deterministic unit tests, modeling failure scenarios, and dealing with costly or rate‑limited third‑party APIs, as long as they’re complemented by integration and end‑to‑end tests. The prevailing view is that there’s no one-size-fits-all answer: good testing balances real-system tests with carefully scoped test doubles, guided by context, architecture, and risk.
Role of mocking
- Many see mocks as a useful tool to isolate a “unit” from its dependencies, make tests deterministic, and express specific scenarios (including error paths).
- Others argue mocks are often misused: tests end up asserting on mocks rather than behavior, or mirroring the implementation, making them brittle and low-value.
- A recurring criticism: mocks rarely cover real edge cases; they model a “happy path” view of dependencies, so they miss bugs that occur with real systems.
Databases and I/O
- Strong sentiment that mocking databases is usually a footgun. Real databases (often via Docker/TestContainers) are now easy enough to run and better reflect production behaviors (transactions, isolation, collation, triggers, performance).
- Various strategies discussed: per-test schemas or databases, wrapping tests in transactions and rolling back, seeding via SQL fixtures or helper code, using anonymized production dumps, and even snapshotting production replicas.
- Some note managed DBs (e.g., cloud offerings) can differ from local instances, so tests must align with the actual runtime environment.
Third‑party APIs and failure cases
- For complex or rate‑limited external APIs, mocks or recorded responses (e.g., VCR‑style tools) are seen as necessary to avoid instability, cost, and rate limits.
- Others report success running E2E tests directly against real sandbox APIs, with few issues.
- Mocks/fakes are widely viewed as the most practical way to test rare or hard‑to‑trigger failures (HTTP 500s, timeouts, malformed data, payment gateway quirks).
Test strategy and layering
- Broad agreement that no single style is sufficient: combine unit tests (often with mocks/fakes) with integration and E2E tests (real dependencies).
- Several reference the testing “pyramid” and suggest prioritizing integration/E2E if time is limited, while still valuing targeted unit tests for quick diagnostics.
Design, testability, and documentation
- Heavy reliance on mocks is seen by some as a design smell: indicates poor separation of logic and I/O, excessive statefulness, or tight coupling.
- Dependency inversion and clear boundaries can reduce the need for mocks, or shift toward simpler fakes/data-driven tests.
- Debate over whether unit tests primarily serve as regression guards, executable documentation, or bug-finding tools; most agree they do some of each.
Overall view of the article’s claim
- Many commenters consider “mocking is an anti‑pattern” overly absolutist and misleading.
- Consensus trend: mocking has real costs and is often overused, but remains valuable in specific contexts; “it depends” and good judgment matter more than blanket rules.