We use a hybrid approach:
  • Contract tests (Pact) for service interactions
  • Testcontainers for real dependencies (DB, Kafka, etc.)
  • Lightweight Docker Compose for key end-to-end flows

Avoids over-mocking while keeping tests fast. Full system tests only for critical paths.

This cut down most of our integration surprises.