Integration Testing in .NET: What Unit Tests Don’t Catch
Unit tests are great for validating isolated behavior. But real systems rarely fail in isolation.
Most production bugs happen at the seams: when services talk to databases, queues, APIs, caches, configuration, or serialization layers. That is exactly where integration tests earn their value.
Unit tests give confidence. Integration tests give realism.
A unit test tells you whether a piece of logic behaves correctly in isolation.
An integration test tells you whether your code actually works when real components are involved.
That distinction matters more than most teams realize.
What unit tests usually miss
Even a well-tested codebase can still fail because of:
- incorrect DI registration
- broken EF Core mappings
- JSON serialization mismatches
- configuration binding issues
- unexpected database constraints
- authentication / authorization behavior
These are not theoretical failures. They are extremely common production problems.
Where integration tests are most valuable in .NET
In backend-heavy .NET systems, I usually get the most value from testing:
- API endpoints end-to-end
- database interactions
- message consumers and publishers
- background services with dependencies
- configuration and startup wiring
If it depends on multiple moving parts, it is a strong candidate for integration testing.
Use integration tests to validate wiring, not everything
One common mistake is trying to test every single path through integration tests. That becomes slow, noisy, and hard to maintain.
A better approach is:
- Use unit tests for behavior-heavy logic
- Use integration tests for boundaries and system wiring
That split tends to age much better.
What good .NET integration tests usually include
- real application startup
- real dependency injection
- test database or isolated test store
- real serialization and request/response flow
The goal is not “full production parity.” The goal is to catch the kinds of issues unit tests cannot see.
Fast enough to run, realistic enough to matter
Integration tests should not be painfully slow. If they are too expensive, developers stop trusting or running them.
The sweet spot is:
- small in number
- high in value
- focused on failure-prone paths
You do not need hundreds. You need the right ones.
My rule of thumb
If a bug could happen because multiple components are connected incorrectly, a unit test is probably not enough.
That is where integration testing belongs.
Final takeaway
Unit tests protect your logic. Integration tests protect your assumptions.
And in real systems, bad assumptions break production just as fast as bad code.