Integration Testing
Tests that verify your code works correctly with real infrastructure like databases and message brokers.
Integration tests verify that your code works correctly with real infrastructure: databases, message brokers, HTTP APIs, and other external systems. Unlike unit tests, they don't mock these dependencies.
A mocked database won't catch a broken migration, a wrong SQL query, or a concurrency issue. When the test hits a real PostgreSQL instance, you can catch these problems before production. Use Docker to spin up infrastructure for tests.
The key to making integration tests practical is speed. They need to run fast enough that developers actually use them.
Integration tests work best at the adapter layer: repositories, API clients, and message publishers. Test that your repository correctly stores and retrieves data, handles edge cases, and respects constraints. Don't test business logic here. That belongs in unit tests.
Component tests take integration testing further by spinning up the entire service and testing through its public API. Integration tests focus on individual adapters, while component tests verify the whole service works together.
References
- 4 practical principles of high-quality database integration tests in Go — Covers testing repositories against real databases, using shared test suites across implementations, and keeping tests fast with Docker.
- Microservices test architecture. Can you sleep well without end-to-end tests? — Explains where integration tests fit in the testing pyramid for microservices, alongside component tests and end-to-end tests.
- Running integration tests with docker-compose in Google Cloud Build — Shows how to run integration tests with docker-compose in a CI/CD pipeline, testing against real dependencies like databases and message brokers.
- Optimising and Visualising Go Tests Parallelism: Why more cores don't speed up your Go tests — Discusses organizing tests by type, including integration tests in separate packages, and optimizing parallel test execution.
- Database Transactions in Go with Layered Architecture — Explains how passing SQL transactions through layers forces what should be a unit test into an integration test, and how Clean Architecture avoids this problem.
- How to implement Clean Architecture in Go (Golang) — Shows how Clean Architecture improves testability. Before the refactoring, the only way to test the code was with integration tests requiring a running database.
- GitLab CI tips for building custom workflows — Covers running integration tests that use external resources like databases and HTTP services in GitLab CI pipelines.
- Is Clean Architecture Overengineering? — Discusses how adapters are a good fit for integration tests, running Docker databases to test repositories in isolation from the domain layer.
- Event-Driven Architecture: The Hard Parts — Mentions how component tests fill the gap between end-to-end and integration tests when working with event-driven systems.