DEV Community

Cover image for The Best Engineers I Know Don't Write Unit Tests
Tarek Mostafa
Tarek Mostafa

Posted on

The Best Engineers I Know Don't Write Unit Tests

Last year, a critical payment processing service went completely silent during Black Friday traffic.
Transactions stalled. Errors spiked. The team scrambled.
The craziest part?
Code coverage was 94%. Every single CI unit test pipeline was glowing green.
The database timeout was mocked. The third-party payment gateway was mocked. The Redis distributed lock was mocked. The pipeline happily verified that our imaginary world of fake dependencies worked in complete harmony.
Meanwhile, in the cold, unyielding reality of production, the system was dead on arrival.
Over the last decade working across high-scale distributed systems, I noticed a pattern that feels like heresy to say out loud in modern agile culture:
The most effective, battle-tested software engineers I know almost never write traditional unit tests.
Here is why—and what they build instead.

1. The Mocking Industrial Complex

Somewhere around 2014, the software industry conflated testing with mocking.
Today, a typical "unit test" in enterprise software looks like this:

  • 40 lines of setup configuring mocks, stubs, and synthetic responses.
  • 3 lines invoking the actual method.
  • 15 lines asserting that mockService.call() was called exactly once with specific parameters. Ask yourself: What did this test actually prove? It proved that your code calls the mock the way you told the mock to expect to be called. That’s not a test; that’s circular reasoning disguised as quality assurance. Even worse, these tests couple directly to implementation details, not behavior. The moment an engineer attempts to refactor internal logic without changing external contracts, 18 unit tests explode with red errors. Unit tests don't make code safe to refactor. In most codebases, they freeze bad architecture in place.

2. Testing Your Assumptions Against Your Own Assumptions

The fatal flaw of the isolated unit test is simple:

A unit test cannot verify reality. It can only verify your imagination of reality.
If you believe Postgres behaves in a certain way when a unique constraint collides during a concurrent transaction, you configure your mock to mirror that belief.
If your belief is wrong, your unit test passes, your CI merges the PR, and production crashes at 2:00 AM.
Real production bugs in modern software rarely happen because a simple calculation was wrong. They happen at the boundaries:

  • Network timeouts and retry storms.
  • Race conditions between distributed workers.
  • Serialization mismatches between microservices.
  • Database locking behaviors under high concurrency. Unit tests, by definition, eliminate the boundaries. They test the logic in vacuum, precisely where it is least likely to fail in catastrophic ways.

3. Code Coverage is a Vanity Metric That Breeds Cynicism

When management mandates "85% Unit Test Coverage," they think they are buying reliability.
What they are actually buying is test theater.
Developers are smart creatures who respond to incentives. When you mandate an arbitrary percentage, engineers stop thinking about risk and start thinking about lines executed. They write tests for getters, boilerplate mappers, and trivial orchestrators.
They write tests with zero meaningful assertions just to turn lines green in SonarQube.
It eats up 30% of engineering bandwidth, inflates CI run times, and gives the business a false sense of security.

4. What Elite Engineers Do Instead

If they aren't writing unit tests, are they just cowboy coding directly to main?
Absolutely not. The best engineers are obsessed with correctness—they just place their bets where the return on investment (ROI) is exponentially higher.
Here is what replaces the unit test frenzy:

A. Real Boundary Verification (Testcontainers & Ephemeral Envs)

Instead of mocking the database or Kafka, they spin up a lightweight, real instance using tools like Testcontainers.
If a test passes, they know with 100% certainty that the actual SQL migration, indices, and driver semantics work against an actual database engine. One real integration test is worth fifty mocked unit tests.

B. Making Illegal States Unrepresentable

Instead of writing 15 unit tests checking for null, invalid negative values, or malformed states, they encode those invariants directly into the type system and domain value objects.
If the compiler won't allow an invalid order state to exist, you don't need a unit test to verify what happens when it does.

C. Contract Testing Over Synthetic Mocks

When services talk to each other, they don't mock the downstream API. They use tools like Pact or schema registry validation to enforce strict, bi-directional contracts. If an upstream service changes a JSON key, the contract test fails before deployment.

D. Production Resilience & Observability

They understand that no test suite captures the chaos of real human users. So they invest the time they saved from writing trivial mocks into:

  • Fine-grained structured logging and distributed tracing.
  • Automated canary rollouts and instant rollback triggers.
  • Circuit breakers and graceful degradation fallbacks. If your system can automatically isolate a failing microservice without taking down the checkout flow, you don't need to panic about whether every internal helper function had 100% test coverage.

The Uncomfortable Truth

Unit tests are fantastic for isolated algorithms: cryptographic functions, regex parsers, financial amortization calculations, and pure mathematical operations.
If you are writing pure logic, write unit tests.
But 90% of modern software engineering is not algorithmic; it is plumbing and integration. It is orchestrating databases, cloud services, external APIs, and state transitions.
Mocking the world to claim you tested the plumbing is just professional delusion.
Stop measuring how many lines of code you tested in a vacuum. Start measuring how fast your system recovers when the real world refuses to behave like your mocks.

What’s your stance?
Do you still enforce 80%+ unit test coverage on your team, or have you shifted your focus to integration and production observability? Let’s debate in the comments.

Top comments (0)