Testing and Code Review

Integration and System Testing in Plain Terms

How testing combined components differs from testing single units, what integration and system tests each catch, and when it is worth using each level.

On this page
  1. Why single-part tests are not enough
  2. Integration testing
  3. System testing
  4. What each level catches
  5. Choosing the balance
  6. Limits to keep in mind

Why single-part tests are not enough

Imagine two components that each pass all of their own tests. One produces a date as text, and the other reads a date as text. Both seem fine until it turns out that one writes day-month-year and the other expects month-day-year. Neither component is wrong in isolation. The mistake lives in the agreement between them.

This pattern is common. Unit tests check that a small piece behaves as its author intended. They cannot tell you whether the pieces were intended to fit together in the same way. That is what integration and system testing are for.

Integration testing

Integration testing checks that two or more components work correctly when combined. The scope is deliberately limited: usually one connection or one small group of parts, not the entire product.

Typical examples:

  • Code that saves and reads records through a real database.
  • A module that calls another module, with both real.
  • Software that reads from or sends commands to a device or another service.
  • A web service handling a request and returning the response the caller expects.

What integration tests tend to catch:

  • Mismatched assumptions about formats, units, ordering or the meaning of fields.
  • Wrong or missing configuration, such as an incorrect connection setting.
  • Error handling across a boundary, for example what happens when the other side is slow, unavailable or returns something unexpected.
  • Data that survives one step but is damaged in the next, such as characters lost when text passes through a layer.

Because many faults sit at boundaries, many engineers find that interfaces deserve extra attention in any design; the same idea appears in systems engineering when people look at system interfaces.

Approaches to combining parts

Teams combine components in different ways. Some join everything at once and test the result, which is simple but makes failures hard to locate. Others add one component at a time, testing at each step, so a new failure points to the newest addition. Incremental combination is usually easier to debug, although it takes more planning.

Test doubles

Sometimes a real dependency is impractical: it is slow, costs money, is not available yet or cannot be made to fail on demand. A test double, such as a stub or a fake, stands in for it. Doubles make tests faster and more controllable, but they carry a risk: the double only behaves as well as the author’s understanding of the real thing. If that understanding is wrong, the tests pass and the real combination still fails. Many projects keep at least a few tests against the real dependency for this reason.

System testing

System testing exercises the complete, assembled product in an environment that resembles real use, judging it from the outside, as a user or a connected system would. It asks whether the whole thing meets its requirements.

System tests typically cover:

  • Complete user journeys from start to finish.
  • Behaviour across all components, including start-up and shut-down.
  • Non-functional properties such as response time, behaviour under load, recovery after failure and resource use.
  • Compatibility with the platforms and configurations that the product must support.

Because they involve everything, they catch problems that smaller tests structurally cannot, such as an unexpected interaction between two features or a performance problem that appears only with realistic amounts of data. They are also the slowest, the most expensive to maintain and the hardest to diagnose. A system test failure says that something is wrong somewhere; finding where may take real investigation, using the techniques described under debugging strategies.

For products with hardware, the equivalent step often involves physical equipment, which brings its own planning needs.

What each level catches

Level Typical scope Tends to catch Typical cost
Unit One function or class Logic errors, boundary mistakes Low, fast
Integration A few components together Interface mismatches, configuration, boundary errors Medium
System The whole product Feature interactions, end-to-end flaws, performance High, slow

No level replaces the others. A failure in a system test that no unit or integration test predicted is a hint that a lower-level test is missing, and adding one often makes the problem easier to prevent next time.

Choosing the balance

A common recommendation is to have many unit tests, fewer integration tests and a small number of system tests, because lower-level tests are faster and more precise. That is a guideline rather than a rule. A product that is mostly a thin layer connecting external services may reasonably have little interesting logic to unit test and more value in integration checks.

Some practical points:

  • Keep each integration test focused on one connection so failures are easy to explain.
  • Make test environments repeatable. Tests that depend on a shared database in an unknown state tend to become unreliable.
  • Reserve system tests for the journeys that matter most to users and the risks that matter most to the business.
  • Run the quick tests on every change and the slower ones less often, using an automated pipeline such as the one described under continuous integration.
  • Link tests back to what they verify; the habit of tracing requirements to tests helps show which requirements have system-level checks and which do not.

Limits to keep in mind

Combined-component tests are more realistic, but they are not complete. An environment that resembles production is still not production, and some failures only appear under real conditions or rare timing. Where software is involved in safety-critical or regulated work, the amount and type of testing is often set by standards that differ by country and industry, so follow those and the qualified people responsible for them rather than relying on a general guide.

The complete guide to testing and code review

Software Testing Concepts Every Engineer Should Know
Read the guide

Keep exploring

Guides from other topics

All topics →