DEV Community

Alex Spinov
Alex Spinov

Posted on

Testcontainers Has a Free API: Integration Tests With Real Databases in Docker

Testcontainers spins up real Docker containers for your integration tests — PostgreSQL, Redis, Kafka, Elasticsearch, anything with a Docker image. No mocks, no test doubles, just real services.

Why Testcontainers?

  • Real services — test against actual Postgres, Redis, Kafka
  • No mocks — catches integration bugs that mocks miss
  • Automatic cleanup — containers destroyed after tests
  • Multi-language — Java, Go, Python, Node.js, Rust, .NET
  • Testcontainers Cloud — no local Docker needed

Python

pip install testcontainers
Enter fullscreen mode Exit fullscreen mode
from testcontainers.postgres import PostgresContainer
from testcontainers.redis import RedisContainer
import psycopg2
import redis

def test_postgres():
    with PostgresContainer("postgres:16") as postgres:
        conn = psycopg2.connect(postgres.get_connection_url())
        cur = conn.cursor()

        cur.execute("CREATE TABLE users (id SERIAL, name TEXT)")
        cur.execute("INSERT INTO users (name) VALUES ('Alice')")
        cur.execute("SELECT name FROM users")

        assert cur.fetchone()[0] == 'Alice'
        conn.close()

def test_redis():
    with RedisContainer("redis:7") as redis_container:
        client = redis.Redis(
            host=redis_container.get_container_host_ip(),
            port=redis_container.get_exposed_port(6379)
        )
        client.set('key', 'value')
        assert client.get('key') == b'value'
Enter fullscreen mode Exit fullscreen mode

Node.js

npm install testcontainers
Enter fullscreen mode Exit fullscreen mode
import { PostgreSqlContainer } from '@testcontainers/postgresql';
import { RedisContainer } from '@testcontainers/redis';
import pg from 'pg';
import { createClient } from 'redis';

describe('Integration tests', () => {
  test('PostgreSQL', async () => {
    const container = await new PostgreSqlContainer().start();
    const client = new pg.Client({ connectionString: container.getConnectionUri() });
    await client.connect();

    await client.query('CREATE TABLE users (id SERIAL, name TEXT)');
    await client.query("INSERT INTO users (name) VALUES ('Alice')");
    const result = await client.query('SELECT name FROM users');

    expect(result.rows[0].name).toBe('Alice');

    await client.end();
    await container.stop();
  });

  test('Redis', async () => {
    const container = await new RedisContainer().start();
    const client = createClient({ url: container.getConnectionUrl() });
    await client.connect();

    await client.set('key', 'value');
    expect(await client.get('key')).toBe('value');

    await client.disconnect();
    await container.stop();
  });
});
Enter fullscreen mode Exit fullscreen mode

Go

package main_test

import (
    "context"
    "testing"

    "github.com/testcontainers/testcontainers-go"
    "github.com/testcontainers/testcontainers-go/modules/postgres"
    "github.com/jackc/pgx/v5"
)

func TestPostgres(t *testing.T) {
    ctx := context.Background()

    pgContainer, err := postgres.Run(ctx, "postgres:16",
        postgres.WithDatabase("test"),
        postgres.WithUsername("test"),
        postgres.WithPassword("test"),
    )
    if err != nil {
        t.Fatal(err)
    }
    defer pgContainer.Terminate(ctx)

    connStr, _ := pgContainer.ConnectionString(ctx, "sslmode=disable")
    conn, _ := pgx.Connect(ctx, connStr)
    defer conn.Close(ctx)

    _, err = conn.Exec(ctx, "CREATE TABLE users (id SERIAL, name TEXT)")
    if err != nil {
        t.Fatal(err)
    }

    var name string
    conn.Exec(ctx, "INSERT INTO users (name) VALUES ('Alice')")
    conn.QueryRow(ctx, "SELECT name FROM users").Scan(&name)

    if name != "Alice" {
        t.Errorf("expected Alice, got %s", name)
    }
}
Enter fullscreen mode Exit fullscreen mode

Available Modules

Module Image
PostgreSQL postgres:16
MySQL mysql:8
Redis redis:7
Kafka confluentinc/cp-kafka
Elasticsearch elasticsearch:8
MongoDB mongo:7
RabbitMQ rabbitmq:3
MinIO minio/minio
Localstack localstack/localstack

Resources


Need testing tools or data automation? Check my Apify actors or email spinov001@gmail.com.

Top comments (0)