Software testing guide

Basics

Levels of Software Testing

Levels describe how much of the system is exercised together: tiny pieces, collaborating modules, the whole product, or business-ready flows. Each level finds different bugs.

Reading time ~13 minutes · Last updated May 3, 2026

Simple picture: bricks, rooms, housewarming

  • Unit: verify each brick snaps correctly—inputs and outputs of one function or class.
  • Integration: ensure plumbing between rooms works—API contracts, queues, databases cooperating.
  • System: walk through the furnished house end-to-end as a renter would—full environments, realistic data volumes.
  • Acceptance: the family decides whether they will actually move in—business or user criteria, sometimes contractual.

Definitions with concrete examples

Unit testing

Fast, isolated checks—often with mocks/fakes—proving algorithms and edge cases. Example: tax rounding helper returns correct cents for each bracket boundary.

Integration testing

Validates interfaces between components or services. Example: order service publishes events consumed by inventory with correct idempotency keys.

System testing

Executes against the integrated application in production-like settings—functional and non-functional angles. Example: disaster-recovery drill restores databases within RPO/RTO budgets while dashboards stay accurate.

Acceptance testing

Confirms the system satisfies agreed acceptance criteria—User Acceptance Testing (UAT), contractual checklists, regulatory sign-offs, or beta cohort feedback programmes.

Test pyramid (guideline, not gospel)

Visualise many cheap unit tests at the base, fewer integration checks in the middle, and the smallest count of fragile UI end-to-end suites at the top. Pyramids promote fast feedback and pinpoint failures—but microservices and rich frontends sometimes justify “diamond” shapes with heavier integration layers when contracts stabilise later.

Worked example: ecommerce promo engine

  • Unit: percentage-off calculator respects caps and currency rounding.
  • Integration: promo microservice reads catalogue Redis cache with graceful degradation when stale.
  • System: storefront, payments, and fulfilment orchestrate a weekend sale under load tests.
  • Acceptance: merchandising approves screenshot-evidence plus analytics dashboards matching contractual KPI reporting.

Expert angle: shifting boundaries

Contract tests and consumer-driven contracts blur traditional integration boundaries. Observability-driven testing lifts production traffic replay into “system” validation without staging clones. Naming debates matter less than clarity about scope, data realism, and defect isolation goals per suite.

Takeaways

  • Move left with fast feedback loops; reserve expensive levels for holistic risks.
  • Choose data and environment fidelity deliberately—integrated cans of worms hide behind “realistic enough.”
  • Acceptance belongs to stakeholders; testers facilitate evidence they trust.