Integration Test
A test of several components working together.
Also known as: integration testing, integration tests
An integration test checks that several pieces work together: your code and the database, two modules, or your service and a queue. A unit test checks one piece in isolation; an integration test checks the connections between them.
Many bugs live in those connections: a wrong column name, a missing migration, a query that works on paper but returns the wrong rows, a serialization mismatch.
def test_repository_saves_and_loads_user(db_session):
repo = UserRepository(db_session) # real repository, real (test) database
repo.save(User(email="ana@example.com"))
loaded = repo.find_by_email("ana@example.com")
assert loaded is not None
assert loaded.email == "ana@example.com"
A unit test with a mocked database couldn’t have caught a broken SQL query here. This one can.
Practical points
- Use a real but disposable dependency: a test database, or a container started by Testcontainers.
- Keep tests independent: set up your own data, and clean up (or roll back a transaction) afterwards.
- They’re slower than unit tests, so write fewer, aimed at boundaries: database access, external APIs, message handling. The testing pyramid suggests many unit tests, fewer integration tests, and fewer still end-to-end ones.
- Don’t mock the thing you’re integrating with, or you’re back to a unit test.
API tests are a common form: they cover routing, validation and the database in one go.