Skip to content

Testing

Software testing is the practice of gathering evidence that a system behaves the way it is supposed to — and of finding the ways it does not. This guide is a complete, bilingual map of the types of testing, the frameworks and tools that implement each type, and short setup examples in several languages.

  • Testing Approaches — the vocabulary: black-box vs white-box, TDD, BDD, manual vs automated.
  • If you are new, read the Fundamentals first, then skim the categories below.

Testing types overlap, and a single test can belong to several categories at once. The map below groups them by the question each answers.

Category Question it answers Types
Fundamentals At what scope am I testing? Static analysis, Unit, Integration, Component, Contract, End-to-End, System
Functional Does it do the right thing? Smoke, Sanity, Regression, Acceptance, Exploratory
Non-Functional Does it do it well? Performance, Security, Accessibility, Reliability & Chaos, Compatibility, Usability
Advanced How much of the input space is covered? Property-based, Mutation, Fuzz, Snapshot, Visual regression
Specialized Which surface or platform? API, Database, Mobile, Cross-browser, i18n / L10n
Tooling What runs and reports it? Test runners, Coverage & reporting, CI & synthetic monitoring, Test management

The classic test pyramid says: many fast unit tests at the base, fewer integration tests in the middle, a small number of slow end-to-end tests on top.

/\ E2E (few, slow, brittle, high confidence)
/ \
/----\ Integration (some, medium)
/ \
/--------\ Unit (many, fast, cheap)
/----------\

The testing trophy (Kent C. Dodds) rebalances this for modern UI work, putting integration tests — testing several units working together the way a user does — at the widest point, supported by static analysis below and a thin E2E layer above.

Neither shape is a law. The right balance depends on your architecture: more E2E when components are hard to test in isolation, more unit/contract when services talk over the network.

  1. Start with static analysis — type checkers and linters catch whole classes of bugs for almost no runtime cost.
  2. Cover logic with unit tests — fast feedback while you code.
  3. Prove seams with integration and contract tests — the places where bugs hide.
  4. Confirm user journeys with a few E2E tests — the paths that must never break.
  5. Add non-functional tests where the risk is — performance, security, a11y.
  6. Push into advanced techniques when you want confidence the tests themselves can catch bugs (mutation) or that inputs are fuzzed (fuzz, property-based).

Self-assessment quiz

Pick one answer per question, then press Check answers.

  1. Which category answers the question "Does the system do it well?" rather than "Does it do the right thing?"
  2. In the classic test pyramid, which layer should contain the GREATEST number of tests?
  3. A test that checks whether a feature still works after a code change is best described as…
  4. Which of these is NOT a non-functional type in this guide?