Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Integration testing is the level of software testing where individual modules or components are combined and tested as a group to expose defects in their interfaces and interactions. It sits between unit testing (which checks each module alone) and system testing (which checks the whole application). The aim is to catch the bugs that only appear when separately built, already unit-tested pieces start talking to one another — wrong data formats, broken API contracts, incorrect call order, and mismatched assumptions.
In this guide we cover what integration testing is, why it matters, the main approaches (big bang versus incremental top-down, bottom-up, and sandwich), how integration testing compares with unit and system testing, a simple worked example, popular tools, best practices, and the mistakes teams make most often. For an even deeper, example-driven treatment, our complete integration testing guide in the Learning Hub is the companion pillar to this answer.
Integration testing is the phase of the testing lifecycle where modules that have already passed unit testing are connected and exercised together. A unit test confirms that a single function, class, or component behaves correctly in isolation, usually with its dependencies replaced by mocks. But a real application is a network of modules that exchange data and call one another. Integration testing verifies that those connections — the interfaces — work as designed.
The defects integration testing targets live between components, not inside them. Common examples include a producer module sending a date as a string while the consumer expects a timestamp, an API returning a 200 status with an empty body the caller never anticipated, a database layer returning columns in a different order than the service expects, or two services disagreeing on units (dollars versus cents). Each module can be flawless on its own and the system can still fail at the seams.
An integration test typically involves at least two real modules — replacing mocks with actual collaborators wherever practical — so the data genuinely flows across the boundary you want to validate. The most familiar form is API testing, where you send a real request from one service to another and assert that the response status, schema, and values are correct.
Skipping integration testing is one of the costliest shortcuts a team can take, because interface defects that escape to production are expensive to diagnose and fix. Integration testing earns its place for several reasons:
There are two broad strategies for combining modules: big bang, where everything is integrated at once, and incremental, where modules are added a few at a time. Incremental approaches split further into top-down, bottom-up, and sandwich (hybrid). To test partially built systems, incremental methods rely on two kinds of dummy modules: stubs and drivers.
In big bang integration, you wait until all modules are complete, then combine them in one step and test the whole assembly together. It needs no stubs or drivers, which makes it simple to set up. The downside is severe: when a test fails, the defect could be in any interface, so isolating its root cause is slow and frustrating. Big bang is practical only for very small systems where all modules are ready at the same time.
Top-down integration starts from the highest-level (controlling) modules and works downward through the call hierarchy. Because lower-level modules may not be finished, you replace them with stubs that return canned responses. As real modules become available, stubs are swapped out one by one. The advantage is that the main control flow and high-level design are validated early; the trade-off is that low-level modules are exercised late, and writing realistic stubs takes effort.
Bottom-up integration is the mirror image: you begin with the lowest-level utility modules and move upward. Since the higher-level callers may not exist yet, you write drivers that invoke the lower modules and feed them test input. This exercises foundational modules thoroughly and early, which is ideal when the core logic is risky. The drawback is that the top-level user-facing behavior is validated only near the end of integration.
Sandwich integration, also called hybrid integration, combines top-down and bottom-up. The system is split into three layers; the top layer is tested top-down (with stubs), the bottom layer is tested bottom-up (with drivers), and they meet at the middle target layer. This lets teams work from both ends in parallel and is well suited to large, layered systems. It is the most complex to coordinate and uses both stubs and drivers, so it demands more planning.
When the "modules" being combined are whole systems or services — for example, an application integrating with a payment gateway, a CRM, and a shipping API — the activity is often called System Integration Testing (SIT). SIT verifies end-to-end data exchange and workflows across independently developed systems, frequently over real network, message-queue, or file-transfer interfaces. It is essentially integration testing scaled up to the system boundary, and it usually runs after component-level integration and before full system testing. See our dedicated guide on what is system integration testing for a deeper look.
Integration testing is one rung on the testing ladder. The list below shows how it differs from the levels immediately around it — unit testing below and system testing above.
For a deeper side-by-side, see the difference between unit testing and integration testing.
Imagine an e-commerce app with two modules: an OrderService that creates orders, and a PaymentService that charges the customer. Each passes its own unit tests. An integration test confirms that when OrderService calls PaymentService, the right amount is charged and the correct status flows back. Below is a small Java-style integration test using two real collaborators rather than mocks.
// Integration test: OrderService talking to a real PaymentService
@Test
public void orderIsPaidAndConfirmed() {
PaymentService payment = new PaymentService(); // real collaborator
OrderService orders = new OrderService(payment); // wire them together
Order order = orders.placeOrder("SKU-42", 2, 19.99); // qty 2 @ 19.99
// The interface between the two modules must agree on the total
assertEquals(39.98, order.getChargedAmount(), 0.001);
assertEquals("CONFIRMED", order.getStatus());
assertTrue(payment.wasCharged(order.getId()));
}If OrderService sent the price in cents while PaymentService expected dollars, both modules' unit tests would still pass, but this integration test would fail on the charged amount — exactly the kind of seam defect integration testing exists to catch.
The right tool depends on your stack and the kind of interface you are testing. Common choices include:
For a broader, curated comparison of options across every stack, see our roundup of the top integration testing tools.
When integration testing reaches the UI layer — confirming the front end, back end, and third-party services all work together — the result can vary by browser, operating system, and device. A flow that integrates perfectly on Chrome for Windows may break on Safari for macOS or on a real Android handset because of rendering, API, or platform quirks.
This is where a cloud grid helps. With TestMu AI, you can run the same integration and end-to-end suites across 3000+ real browser and operating-system combinations on a real device and browser cloud, confirming that integrated modules behave identically everywhere your users are. Pair it with cross browser testing and automation testing to catch environment-specific integration defects before release.
// Run your existing integration/UI suite on the cloud grid
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("browserName", "Safari");
caps.setCapability("platformName", "macOS Ventura");
WebDriver driver = new RemoteWebDriver(
new URL("https://USERNAME:[email protected]/wd/hub"), caps);
// The same end-to-end integration flow now runs on Safari for macOSIntegration testing is the level where individually verified modules are combined and tested as a group to expose defects in their interfaces and interactions. Choose an incremental approach — top-down, bottom-up, or sandwich — over big bang so failures stay easy to locate, use stubs and drivers to test partially built systems, exercise real collaborators wherever practical, and validate UI-level integration across real browsers and devices. Get integration testing right and you stop the costly seam defects that unit and system tests alone would miss.
Integration testing is the level of testing where individual, already unit-tested modules are combined and tested together as a group. Its goal is to expose defects in the interfaces between modules — wrong data formats, broken API calls, or mismatched assumptions — that unit tests cannot catch in isolation.
Unit testing checks a single module in isolation, usually with mocks. Integration testing combines two or more real modules and verifies they work together across their interfaces. Unit tests find logic bugs inside a unit; integration tests find communication bugs between units, like data-format or contract mismatches.
A stub is a dummy that stands in for a lower-level module a tested module calls, used in top-down testing. A driver is a dummy that invokes a lower-level module before its callers exist, used in bottom-up testing. Both let you test partially built systems before every real module is ready.
Incremental approaches such as top-down, bottom-up, or sandwich are generally preferred over big bang because they isolate defects to the most recently added interface, making bugs far easier to locate. Big bang is only practical for very small systems where all modules are ready at once.
Yes. API testing is one of the most common forms of integration testing because it verifies the contract between two services at their interface. Tools like Postman, REST Assured, and Karate send real requests across module boundaries and assert the responses, status codes, and data shapes match expectations.
Integration testing is usually a shared responsibility. Developers write and run integration tests for the interfaces between the modules they build, especially in CI, while QA engineers design broader cross-module and system integration scenarios. On many teams the two collaborate so both code-level and end-to-end interface defects are covered.
System integration testing (SIT) checks that independently developed systems or services — such as an app, a payment gateway, and a CRM — exchange data and workflows correctly across their real interfaces. It is integration testing at the system boundary, typically run after component integration and before full system testing.
KaneAI - Testing Assistant
World’s first AI-Native E2E testing agent.

TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance