Test Levels: Unit, Integration, System, Acceptance
The four traditional test levels, what each one actually catches, and why relying on only one of them leaves real gaps.
What you'll learn
- Name the four traditional test levels and what scope each one covers
- Classify a given test scenario by the level it belongs to
- Explain why a defect can pass unit tests but fail at integration or system level
Prerequisites
Explanation
Two functions can each work perfectly alone and still break the moment they're connected. A payment function correctly calculates a total. A checkout function correctly calls "whatever calculates the total." Plugged together, one expects cents and the other passes dollars — both individually correct, both wrong together. This is exactly why testing happens at more than one level, each with a different scope and a different kind of defect it's positioned to catch.
Unit testing exercises the smallest testable piece of code in isolation — a single function or method — usually by the developer who wrote it, often with dependencies replaced by simple stand-ins. It answers: "does this one piece do what it claims, for the inputs I can enumerate?" It's fast and cheap to run, which is exactly why it's the wrong place to catch a problem that only exists between two pieces.
Integration testing exercises two or more units together, deliberately targeting the seams: does the payment function receive the total in the unit the checkout function actually sends it in? Integration defects are often the most surprising, because each side individually looks correct — the bug lives in the disagreement between them, not inside either piece.
System testing exercises the complete, integrated application against its end-to-end requirements, usually in an environment resembling production. It's the first level where a full user journey — browse, add to cart, pay, receive confirmation — gets exercised as a whole, and where cross-cutting concerns like performance under realistic load first show up meaningfully.
Acceptance testing asks a different question entirely: not "does it work" but "is this what the business actually needed?" It's typically performed by or with stakeholders, checking the system against real-world usage and business requirements before a release decision. A system can pass every unit, integration, and system test and still fail acceptance testing, if it was built precisely to the wrong specification.
The levels are not a strict sequence you complete once and never revisit — in an agile team, all four happen continuously, often for the same feature within the same day. What matters is understanding that each level has a scope, and defects that live outside that scope will simply not be caught there, no matter how thoroughly you test within it.
Example
Each function passes in isolation (unit level) — the mismatch only appears once they're called together (integration level).
// Unit level: each function is correct on its own.
function calculateTotalCents(items) {
return items.reduce((sum, item) => sum + item.priceCents, 0);
}
function chargeCard(amountDollars) {
return `Charging $${amountDollars.toFixed(2)}`;
}
// Integration level: wiring them together reveals the real bug.
const items = [{ priceCents: 500 }, { priceCents: 250 }];
const total = calculateTotalCents(items); // 750 (cents)
console.log(chargeCard(total)); // "Charging $750.00" -- should be $7.50!Try it yourself
Fix the integration bug by converting cents to dollars before calling chargeCard, then re-run.
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Guided exercise
Guided exercise
Classify each scenario by test level using the strings 'unit', 'integration', 'system', or 'acceptance': scenarioA = testing a single validateEmail() function with 10 sample emails. scenarioB = a product manager checks the finished app against the original business goals before sign-off.
Checks: correctly classifies scenario A as unit · correctly classifies scenario B as acceptance
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Independent exercise
Independent exercise
Classify two more scenarios the same way: scenarioC = verifying the checkout module correctly calls the shipping module with the right address format. scenarioD = running the full purchase flow (browse, cart, pay, confirmation email) in a staging environment.
Checks: correctly classifies scenario C as integration · correctly classifies scenario D as system
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Common mistakes
- Assuming a feature with 100% unit test coverage has no risk left — coverage only measures the unit level's scope.
- Skipping integration testing because "each piece already has unit tests," which is exactly the gap integration testing exists to close.
- Confusing system testing (does the whole app work) with acceptance testing (is the whole app what was actually needed) — a system can pass one and fail the other.
Knowledge check
Takeaway
Each test level has a distinct scope, and a defect outside that scope will not be caught there — real coverage means using multiple levels deliberately, not relying on one.
Summary
This lesson introduced the four traditional test levels — unit, integration, system, and acceptance — what each catches, and why a defect can survive one level and only surface at another.
References
Your notes
Notes save automatically.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.