Files
docker-docs/content/guides/testcontainers-python-getting-started/write-tests.md
Manuel de la Peña 36d384d2da docs(guides): add two testcontainers intro guides (go and python) (#24450)
## Description

Migrate the first two Testcontainers getting-started guides from
[testcontainers.com/guides](https://testcontainers.com/guides/) into the
Docker docs site:

- **Getting started with Testcontainers for Go** — multi-page guide with
4 chapters (create project, write tests, test suites, run tests). Code
updated to testcontainers-go v0.41.0 API (`postgres.Run()`,
`CleanupContainer`, `BasicWaitStrategies()`).
- **Getting started with Testcontainers for Python** — multi-page guide
with 3 chapters (create project, write tests, run tests). Code updated
to testcontainers-python 4.14.2 (fixed `get_exposed_port()` returning
`int`).

Each guide appears as its own entry in the `/guides/` listing with
proper language and tag filters (`testing-with-docker`). Chapters render
with stepper navigation in the sidebar.

Also adds:
- A `testing-with-docker` tag to `data/tags.yaml`
- A Claude skill
(`.claude/skills/testcontainers-guides-migrator/SKILL.md`) that
documents the repeatable migration process for the remaining 19 guides
- Links from `content/manuals/testcontainers.md` to the new guides
- Vale vocabulary entries for `pgx`, `Micronaut`, `psycopg`, `pytest`

All guide code was compiled and tests verified passing in containers
with Docker socket mounted.

## Related issues or tickets

No related issues found.

## Reviews

- [ ] Technical review
- [ ] Editorial review
- [ ] Product review
2026-03-23 13:58:19 +00:00

3.1 KiB

title, linkTitle, description, weight
title linkTitle description weight
Write tests with Testcontainers Write tests Write integration tests using testcontainers-python and pytest with a real PostgreSQL database. 20

You'll create a PostgreSQL container using Testcontainers and use it for all the tests. Before each test, you'll delete all customer records so that tests run with a clean database.

Set up pytest fixtures

This guide uses pytest fixtures for setup and teardown logic. A recommended approach is to use finalizers to guarantee cleanup runs even if setup fails:

@pytest.fixture
def setup(request):
    # setup code

    def cleanup():
        # teardown code

    request.addfinalizer(cleanup)
    return some_value

Create the test file

Create a tests/__init__.py file with empty content to enable pytest auto-discovery.

Then create tests/test_customers.py with the fixtures:

import os
import pytest
from testcontainers.postgres import PostgresContainer

from customers import customers

postgres = PostgresContainer("postgres:16-alpine")


@pytest.fixture(scope="module", autouse=True)
def setup(request):
    postgres.start()

    def remove_container():
        postgres.stop()

    request.addfinalizer(remove_container)
    os.environ["DB_CONN"] = postgres.get_connection_url()
    os.environ["DB_HOST"] = postgres.get_container_host_ip()
    os.environ["DB_PORT"] = str(postgres.get_exposed_port(5432))
    os.environ["DB_USERNAME"] = postgres.username
    os.environ["DB_PASSWORD"] = postgres.password
    os.environ["DB_NAME"] = postgres.dbname
    customers.create_table()


@pytest.fixture(scope="function", autouse=True)
def setup_data():
    customers.delete_all_customers()

Here's what the fixtures do:

  • The setup fixture has scope="module", so it runs once for all tests in the file. It starts a PostgreSQL container, sets environment variables with the connection details, and creates the customers table. A cleanup function removes the container after all tests complete.
  • The setup_data fixture has scope="function", so it runs before every test. It deletes all records to give each test a clean database.

Write the tests

Add the test functions to the same file:

def test_get_all_customers():
    customers.create_customer("Siva", "siva@gmail.com")
    customers.create_customer("James", "james@gmail.com")
    customers_list = customers.get_all_customers()
    assert len(customers_list) == 2


def test_get_customer_by_email():
    customers.create_customer("John", "john@gmail.com")
    customer = customers.get_customer_by_email("john@gmail.com")
    assert customer.name == "John"
    assert customer.email == "john@gmail.com"
  • test_get_all_customers() inserts two customer records, fetches all customers, and asserts the count.
  • test_get_customer_by_email() inserts a customer, fetches it by email, and asserts the details.

Because setup_data deletes all records before each test, the tests can run in any order.