Skip to content

ADR-007: Testcontainers — Containerized Integration Tests

Date: 2026-02-24 Authors: Jean-Francois Meyers Scope: granit-dotnet (Granit.Wolverine.Postgresql.IntegrationTests)

Granit integration tests require a real PostgreSQL database to validate DBMS-specific behaviors: EF Core migrations, Wolverine outbox, multi-tenant global filters, JSONB queries, etc.

In-memory alternatives (EF Core InMemory, SQLite) do not faithfully reproduce PostgreSQL behavior and mask bugs that only appear in production.

Testcontainers (Testcontainers.PostgreSql) to orchestrate ephemeral PostgreSQL containers in integration tests.

  • License: MIT
  • Advantage: real PostgreSQL container started on demand, complete isolation per test, automatic cleanup, .NET fluent API, xUnit support via IAsyncLifetime
  • CI: compatible with GitHub Actions (service containers) and GitLab CI
  • Advantage: fast, zero infrastructure dependency
  • Disadvantage: no real SQL (no migrations, no FK constraints, no JSONB, no transactions), false sense of confidence, bugs masked in production
  • Advantage: real SQL without a server, fast
  • Disadvantage: SQL dialect different from PostgreSQL (no JSONB, no schemas, different types), non-portable migrations, different transactional behavior
  • Advantage: no Docker, speed (no container startup)
  • Disadvantage: shared state between tests (difficult isolation), manual cleanup, non-reproducible CI (depends on external server), conflicts between developers
CriterionTestcontainersInMemorySQLiteShared DB
PostgreSQL fidelityFullNonePartialFull
IsolationPer testPer testPer testDifficult
CI reproducibilityYesYesYesNo
SpeedMedium (~3-5s init)Very fastFastFast
Zero external infraYes (Docker)YesYesNo
EF Core migrationsYesNoPartialYes
  • Tests faithful to production behavior (real PostgreSQL)
  • Complete isolation: each test suite has its own database
  • Reproducible CI without external dependency
  • Early detection of DBMS-related bugs (types, constraints, transactions)
  • Requires Docker on development machines and in CI
  • Container startup time (~3-5 seconds per test suite)
  • Higher memory consumption than in-memory alternatives