Testing levels distribute checks across system layers. Different defects are detected more cheaply and reliably at different levels: some within a function, some at integration boundaries, and others only in a user journey.
The main levels
- →Unit testing checks individual functions, methods, or classes in isolation.
- →Integration testing checks interactions among modules, services, databases, queues, and external dependencies.
- →System testing evaluates the complete product with its business logic and environment.
- →Acceptance testing checks whether the solution meets user or business expectations and is ready for acceptance.
What each level provides
- →Unit: fast, inexpensive feedback on low-level logic failures.
- →Integration: protection against contract, data, and component-interaction problems.
- →System: complete user scenarios and end-to-end behavior.
- →Acceptance: confirmation that the team solves the right problem as well as implementing it correctly.
Why one level is insufficient
- →Unit tests do not reveal integration failures between services.
- →System tests are too expensive and fragile to cover every rule.
- →Acceptance testing without technical levels often provides feedback too late.
- →Imbalance creates blind spots or an excessively expensive regression suite.
A QA perspective
- →For every risk, ask which level will detect it earlier, more cheaply, and more reliably.
- →Plan checks for contracts, data, rules, and integrations alongside the UI.
- →Use levels strategically rather than as a requirement to test everything everywhere.
📐
If a risk can be detected earlier at a lower level, there is little reason to wait for it to surface in the UI or a full end-to-end scenario.