CodePark/ questions / Databases, Testcontainers & test data
START PRACTICINGPRACTICE
Backend question · Backend testing › Databases, Testcontainers & test data

What is Testcontainers, and how would you use it to run integration tests against a real Postgres and Redis?

import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';

let pg: StartedPostgreSqlContainer;

beforeAll(async () => {
  pg = await new PostgreSqlContainer('postgres:16-alpine').start();
  process.env.DATABASE_URL = pg.getConnectionUri();
  // run migrations, then build the Nest app or repositories
}, 60_000);

afterAll(async () => {
  await pg.stop();
});

Testcontainers is a library that starts real dependencies in throwaway Docker containers from your test code. It waits until each container is ready. Then it tells you the mapped host and port.

It also keeps tests safe:

  • Containers get random host ports, so parallel runs don't clash.
  • A reaper container called Ryuk removes the containers if the test process dies.

How to use it:

  • Start the container in beforeAll, or once in Jest's globalSetup.
  • Pass its connection URI to the app through config.
  • Run your real migrations.
  • Build the Nest app or the repositories as usual.

Redis works the same way, with @testcontainers/redis or a GenericContainer. Give beforeAll a longer timeout, because the first run must download (pull) the image.

The cost: a few seconds of start-up, and Docker must be on dev machines and in CI. In return, you test against the same Postgres version, extensions and SQL as production.

  • Testcontainers starts real dependencies in disposable Docker containers from test code.
  • Containers get random host ports and are cleaned up automatically.
  • Start a container once per file or in global setup, pass its URI to the app and run migrations.
  • It costs start-up time and needs Docker, but gives production-like behaviour.