Integration test
in-teh-GRAY-shun test
An automated test that verifies multiple components or services work correctly together.
An integration test verifies that different parts of your system work together correctly. Unit tests check individual functions in isolation. Integration tests check that those functions, plus the database, the API layer, the authentication system, and the message queue all cooperate as expected.
These tests answer questions that unit tests cannot. Does the SQL query actually return the right data? Does the API serialize the response correctly? Does the authentication middleware reject expired tokens? Does the payment service handle webhook callbacks from Stripe? Each component might work perfectly in isolation and fail when connected to the real dependencies.
Integration tests are slower and more complex than unit tests. They need databases, sometimes running in Docker containers. They need test data setup and teardown. They are flakier because they depend on network calls and shared state. But they catch an entire category of bugs that unit tests miss. The common advice is the testing pyramid: many unit tests, fewer integration tests, and even fewer end-to-end tests. But the exact ratio depends on your architecture. A system with heavy database logic needs more integration tests. A system with complex algorithms needs more unit tests.
Examples
An integration test catches a database query bug.
The unit tests mock the database and pass. The integration test runs the actual query against a PostgreSQL container. The query uses a LIKE clause that behaves differently in PostgreSQL than in the mock. The unit test expects 5 results. The integration test returns 8 because PostgreSQL's LIKE is case-sensitive by default. The developer switches to ILIKE and both tests pass.
A team tests the full API request lifecycle.
The integration test sends an HTTP request to the running server: POST /api/orders with a JSON body. The test verifies: the response status is 201, the response body contains an order ID, the order exists in the database, and a confirmation email was queued. This single test exercises the router, controller, service layer, database, and event system. It takes 200ms instead of the 5ms a unit test takes, but it catches integration issues.
A team reduces flaky integration tests.
The test suite has 15 integration tests that fail randomly. Investigation reveals: 8 fail due to test order dependencies (shared database state), 4 fail due to timing issues (async operations completing after assertions), and 3 fail due to port conflicts. The team fixes these by using database transactions that roll back after each test, adding proper async awaits, and assigning random ports. Flaky test rate drops from 12% to 0.5%.
In practice
Read more on the blog
Frequently asked questions
Should integration tests use real databases or mocks?
Real databases, almost always. The point of an integration test is to verify that components work together. Mocking the database defeats that purpose. Use Docker containers to run the same database engine as production (PostgreSQL, MySQL, etc.). Tools like Testcontainers make this easy: spin up a fresh database for each test suite, run migrations, seed data, and tear it down when done. The tests take longer but catch real bugs.
How do you keep integration tests fast?
Run them in parallel with isolated databases (each test gets its own schema or transaction). Use database transactions that roll back after each test instead of deleting data. Minimize the number of services involved: test the API and database without starting the frontend. Run only affected integration tests on each PR (based on changed files) and the full suite on main. A well-optimized integration test suite of 200 tests can run in under 2 minutes.
Related terms
An automated test that verifies a small, isolated piece of code behaves correctly.
A metric measuring what percentage of source code is executed by automated tests.
Continuous integration and continuous deployment: automating code testing and delivery to production.
Application programming interface: a defined way for software programs to communicate with each other.
A structured system for storing, organizing, and retrieving data.

Want the complete playbook?
Picks and Shovels is the definitive guide to developer marketing. Amazon #1 bestseller with practical strategies from 30 years of marketing to developers.