Types of Tests and When to Use Them
Unit, integration, E2E, manual, exploratory — every type has its place. Learn the test pyramid vs testing trophy debate and how to make smart trade-offs.
“We should have more tests.”
Every developer has said this after a production incident. But more tests doesn’t mean better tests. The wrong type of test for a given problem is expensive, slow, and ultimately misleading. Understanding when to use which type is one of the most valuable skills in software engineering — and it’s rarely taught explicitly.
In this post I’ll walk through the five core test types, explain the pyramid vs trophy debate, and give you a practical framework for choosing the right tool for the job.
The Five Core Test Types
Unit Tests
A unit test verifies a single unit of code — typically a function, method, or class — in isolation from its dependencies.
Characteristics:
- Fastest to run (milliseconds per test)
- Fully deterministic — no I/O, no network, no database
- Dependencies are replaced with test doubles (mocks, stubs, fakes)
- Easy to diagnose when they fail
When to use: Always, for all business logic. If a function makes a decision, it should have a unit test. This is non-negotiable.
Tools: xUnit, NUnit, MSTest (.NET) · Jest, Vitest (JavaScript) · pytest (Python)
What they miss: Integration problems. A unit test can verify that your code calls a database method correctly — but it won’t tell you if the SQL is wrong.
Integration Tests
An integration test verifies that multiple components work together correctly. This might mean your service + database, two microservices communicating, or your application + a third-party API.
Characteristics:
- Slower than unit tests (seconds per test)
- May involve real I/O — actual DB calls, actual HTTP requests
- More complex setup and teardown
- Higher confidence in system behaviour
When to use: For verifying data flows, contracts between components, and database interactions. After your unit tests give you confidence in logic, integration tests confirm the components connect correctly.
Tools: TestContainers (real DB in Docker for tests) · WebApplicationFactory (.NET in-memory API) · Supertest (Node.js API testing) · RestAssured (Java)
End-to-End (E2E) Tests
E2E tests drive the full system from the user’s perspective — browser to database and back. They simulate what a real user does.
Characteristics:
- Slowest test type (seconds to minutes per test)
- Highest maintenance cost — break on any UI change
- Highest confidence — if this passes, a real user can succeed
- Most prone to flakiness
When to use: Critical user journeys only. Login. Checkout. Core business workflow. Not every button click.
Tools: Playwright · Cypress · Selenium WebDriver
The trap: Teams that write E2E tests for everything end up with suites that take hours, break constantly, and are ignored when they fail. E2E tests are expensive — treat them as expensive.
Manual Testing
Manual testing is human-driven, judgment-based testing. A tester interacts with the system, observing behaviour and applying their experience and intuition.
Characteristics:
- Not automatable by definition — the value is the human judgment
- Best for UX evaluation, accessibility, emotional response
- Good for exploratory sessions on new features
When to use: New features before automation is written. UX and usability evaluation. Accessibility auditing. Acceptance testing with real stakeholders.
The misconception: Manual testing is often seen as a fallback — “we didn’t have time to automate.” But good manual testing is a deliberate, skilled activity. It’s not a lesser form of testing; it’s a different form.
Exploratory Testing
Exploratory testing is simultaneous learning, test design, and test execution. The tester doesn’t follow a script — they use their knowledge of the system to probe areas of risk.
Characteristics:
- Unscripted but structured (test charters provide direction)
- Finds the bugs that scripted tests miss
- High skill requirement — the tester’s knowledge directly affects what they find
- Complements scripted tests; doesn’t replace them
When to use: After new feature releases. After large refactors. Before major releases. When something feels “off” but you can’t articulate what.
I cover exploratory testing in depth in S1-06.
Test Pyramid vs Testing Trophy
This is one of the most debated topics in modern testing strategy. Let me give you both sides fairly.
The Classic Test Pyramid (Mike Cohn, 2009)
/\
/E2E\ ← few, slow, expensive
/------\
/ Integ. \ ← some, medium speed
/------------\
/ Unit Tests \ ← many, fast, cheap
/------------------\
Rationale: Unit tests are cheap to write, cheap to run, and cheap to maintain. The further up the pyramid, the more expensive the test. So have many cheap tests and few expensive ones.
Strengths: Fast CI feedback. Easy to maintain. Clear ownership (developer writes unit tests).
Weaknesses: A system with 2000 unit tests and 5 integration tests can still fail in integration. Unit tests don’t catch “the parts work but don’t fit together.”
The Testing Trophy (Kent C. Dodds, 2018)
/\
/E2E\ ← few
/------\
/ Integ. \ ← MOST tests here
/------------\
/ Unit \ ← some
/------------------\
[ Static Analysis ] ← foundation
Rationale: Integration tests give you the best confidence-to-cost ratio. They test the system close to how it’s actually used, without the overhead and flakiness of E2E.
Quote: “The more your tests resemble the way your software is used, the more confidence they give you.” — Kent C. Dodds
Strengths: High confidence. Tests survive refactors (they test behaviour, not implementation).
Weaknesses: Slower than unit tests. Harder to set up. Less useful for pure business logic.
The Ice Cream Cone (Anti-Pattern)
/------------------------\
/ Manual Testing \ ← many
/----------------------------\
\ E2E Tests / ← some
\--------------------------/
\ Integration / ← few
\----------------------/
\ Unit Tests / ← almost none
\------------------/
Teams end up here by accident: QA does manual testing because “there’s no time to automate,” E2E scripts exist from before anyone cared about performance, and nobody wrote unit tests because “that’s not how we do things here.”
Consequences: Slow CI, flaky tests, high maintenance cost, no fast feedback loop. Every PR takes 30 minutes to verify.
Choosing Your Shape
The honest answer is: it depends. Your test portfolio shape should reflect your architecture, team size, and risk profile.
| Context | Recommended shape |
|---|---|
| Microservices with clear contracts | More integration, fewer E2E |
| Frontend-heavy React app | Testing trophy — component + integration |
| Core business logic library | Pyramid — heavy unit coverage |
| Legacy system with no tests | Start with E2E (smoke), add unit as you refactor |
| Regulated industry | All layers + formal documentation |
Trade-Off Matrix
| Dimension | Unit | Integration | E2E | Manual |
|---|---|---|---|---|
| Speed | ⚡ Fast | 🔶 Medium | 🐢 Slow | 🐢 Slow |
| Cost to write | Low | Medium | High | None |
| Cost to maintain | Low | Medium | High | None |
| Confidence level | Low | Medium | High | High |
| Flakiness risk | Very low | Low-medium | High | N/A |
| Catches integration bugs | ❌ | ✅ | ✅ | ✅ |
| Catches UX issues | ❌ | ❌ | Partial | ✅ |
Practical Recommendations
Before writing any new tests:
- Identify the risk — what is most likely to break? What costs most to miss?
- Choose the lowest-cost test type that adequately covers that risk
- If unit tests give you enough confidence, don’t write an E2E for it
The ROI check: Before automating a test, ask: “How often will this catch a real bug vs. how long will it take to maintain?” If the answer is “rarely” and “often,” don’t automate it. Keep it as a manual check.
Audit what you have: If your team already has a test suite, map it to the shapes above. Which layer is most fragile? Which layer gives you the least value? Start there.
Warning: The ice cream cone is not a strategy. If your CI pipeline takes more than 20 minutes and the slowest step is “run E2E tests,” you have an ice cream cone problem. Fix the test shape before adding more tests.
Conclusion
The “right” test portfolio shape doesn’t exist in the abstract — it exists for your product, your team, your risk tolerance, and your deployment frequency. But the wrong shape has a clear signature: slow builds, ignored failures, and incidents that “should have been caught by tests.”
Start with an audit: draw your current test portfolio shape. Is it a pyramid? A trophy? An ice cream cone? Once you know where you are, you can decide where you want to be — and take one concrete step toward it this sprint.
This is the third post in the Series 1 — QA General series.