Testing Fundamentals

Types of Tests: Unit, Integration, E2E

Understand when to write unit, integration, and end-to-end tests — and why the distinction matters.

Three Types of Tests

Not all tests are equal. Choosing the right type for each scenario determines whether your test suite is a valuable safety net or a slow, brittle burden.

Unit Tests

Unit tests verify a single function, class, or component in complete isolation. All external dependencies are replaced with mocks.

Characteristics: Very fast (milliseconds), very reliable, very cheap to write and maintain.

When to use: Business logic, utility functions, data transformations, algorithms, pure functions.

Integration Tests

Integration tests verify that multiple units work correctly together. They use real dependencies where possible — real database queries, real HTTP calls (to a test server), real file system.

Characteristics: Slower than unit tests (seconds), more realistic, catch interaction bugs.

When to use: API routes, database operations, service-to-service communication.

End-to-End Tests

E2E tests control a real browser and simulate real user actions against your running application.

Characteristics: Slow (seconds to minutes), most realistic, catch the bugs users would actually encounter.

When to use: Critical user flows: signup, login, checkout, core feature paths.

The Testing Trophy

Kent C. Dodds' "testing trophy" suggests writing MORE integration tests than the traditional pyramid suggests. Integration tests give the best return per test — more realistic than unit tests, faster than E2E.

Key Takeaways

  • Unit tests verify isolated functions — fast, cheap, many of them
  • Integration tests verify how components work together — more realistic, medium speed
  • E2E tests verify complete user flows in a real browser — slowest, highest confidence, fewest needed
  • The testing trophy: favor integration tests over unit tests where possible — better confidence per test
  • Never test implementation details — test behavior (what the code does, not how it does it)

Example

typescript
// Three tests for the same feature at different levels
Try it yourself — TYPESCRIPT