← All glossary terms

Integration testing

Integration testing checks separate pieces of a system, like a service and the database it queries, or two internal APIs, work correctly once they're connected. It exists to catch the class of bug that only shows up when components interact, the kind a unit test, run in isolation, was never going to find.

A unit test proves a piece of code does the right thing in isolation, with everything around it replaced by a mock that returns a fixed, predictable value. That isolation is exactly what integration testing removes. Two pieces can each pass their own unit tests perfectly and still fail the moment they're actually wired together, a mismatched data format, a wrong assumption about how the other side behaves, a timing issue that a mock never had to account for.

Scope varies a lot in practice. Integration testing can be narrow, checking two specific modules together, or broad, checking a whole service layer against a real, or realistic, database and message queue. Most teams favor an incremental approach, adding and testing one integration at a time, over a "big bang" approach that wires everything together before testing any of it, since incremental integration makes it far easier to tell which connection actually broke when something fails.

It sits in the middle of the testing pyramid, above unit tests and below full end-to-end tests. There are usually fewer integration tests than unit tests, since they're slower and need more setup, but far more than end-to-end tests, since they check individual connections rather than an entire user journey. That middle position is the point: integration testing catches a wiring-level bug earlier and cheaper than an end-to-end test would, while still exercising the real interaction a unit test skips entirely.


How it's approached

  • Testing two or more real components together, instead of replacing one side with a mock.
  • Favoring an incremental approach, adding and testing one integration at a time, over a "big bang" approach that wires everything up first.
  • Running against a real or realistic version of a dependency, like a test database or a sandboxed third-party API, not a fixed stand-in.
  • Sitting in the middle of the test pyramid, above unit tests and below full end-to-end tests.

Where it shows up

  • Checking that a service correctly reads and writes to its actual database, not a mocked version of it.
  • Verifying two internal microservices agree on the shape of the data they pass between each other.
  • Testing how the application handles a real third-party API's actual responses, including its documented error cases.
  • Catching a mismatch after two teams each finish their own piece and merge them together for the first time.

Benefits and challenges

BenefitChallenge
Catches a class of bug unit testing can't, the kind that only appears when two real pieces actually interact. Slower and more brittle than unit tests, since it depends on a real dependency being available and in a known state.
Builds confidence that components genuinely agree on data formats and behavior, not just what a mock assumed they would. A failing integration test can be harder to debug, the bug could be in either piece, or in the connection between them.
Catches integration issues early, before they reach a slower, more expensive end-to-end test. Needs a realistic test environment, like a real test database, which is more setup than a unit test ever requires.

Frequently asked questions

What's the difference between integration testing and unit testing?

Unit testing checks a single piece of code in isolation, with its dependencies replaced by mocks. Integration testing checks that two or more real pieces work correctly together, which is the exact thing a unit test's isolation is designed to skip.

What's the difference between integration testing and end-to-end testing?

Integration testing usually checks a specific connection, like a service and its database, in relative isolation from the rest of the system. End-to-end testing goes further, walking through a complete user flow across the whole application, touching many integrations along the way rather than testing one connection at a time.

Should integration tests use real dependencies or test doubles?

Generally real, or as close to real as practical, like a dedicated test database or a sandbox version of a third-party API. Using a mock defeats the purpose, since the whole point of integration testing is confirming that the real components actually agree on how they interact.


How Klarent helps

Klarent's AI agents test complete user flows across web, mobile, and API layers, exercising the same real integrations, a service talking to a database, an app calling a live API, that a suite built only on unit tests would never touch.


Ready to eliminate QA bottlenecks? Talk to our team for a personalised walkthrough.

Book a free 30 minute call