# π§ͺ testing-containers
[](https://pypi.org/project/testing-containers/)
[](https://github.com/tedicela/testing-containers/actions/workflows/ci.yml)
[](LICENSE)
> **Lightweight Python utilities for running ephemeral Docker containers in tests.**
> Includes `TestingPostgres` for disposable PostgreSQL test databases and `DockerContainer` for ad-hoc containers.
---
## π Overview
`testing-containers` helps you run **real services inside Docker** for integration or functional tests β without ever needing to manually start external databases, message brokers or anything else.
It provides:
- **`TestingPostgres`** β a PostgreSQL-specific helper that automatically creates a **fresh empty test database** before tests start and tears it down afterwards.
- **`DockerContainer`** β a generic helper to start, stop, and execute commands inside *any* Docker container (Postgres, Redis, LocalStack, etc.).
The goal is simple:
> Make your tests fully isolated, reproducible, and environment-agnostic β no shared state, no external dependencies.
---
## π§ Design Principles
- π§© **No external services** need to be manually started
- π **Fresh empty databases** are created every test run
- π§Ή **Automatic cleanup** when tests finish
- π§± **No pollution of your dev DB** β tests never touch your development data
- βοΈ **Consistent environments** β use the same database version as production via Docker
- π§° **Generic & extensible** β same approach works for PostgreSQL, Redis, LocalStack, RabbitMQ, etc.
- π³ **Only dependency:** Docker (required only when containers are used)
---
## βοΈ Installation
```bash
pip install testing-containers
```
> Requires Docker installed and running if you plan to spin up containerized services.
## π‘ Usage
### `TestingPostgres`
You can use `TestingPostgres` in two ways
**a) Run Postgres inside Docker**
```python
import psycopg
from testing_containers import TestingPostgres, ContainerOptions
pg = TestingPostgres(
    options=ContainerOptions(
        namespace="myproject-name" # optional β you can add a namespace to the container
        name="testdb" # optional β you can give a name to the container
        image="postgres:15.6" # optional / default postgres:16.3
        # The following options defines what should happen on stop()
        # container will stop or not
        # container will be removed or not
        # (you can decide on the speed you want on test startup and teardown)
        should_stop=True # optional / default=False
        remove_on_stop=True # optional / default=False
    )
)  # spins up a postgres:16.3 container
testdb = pg.postgres.testdb  # connection info for your test DB
# Connect and run migrations or tests
conn = psycopg.connect(
    dbname=testdb.name,
    user=testdb.user,
    password=testdb.password,
    host=testdb.host,
    port=testdb.port,
)
print("Connected:", conn)
# After tests
pg.stop()
```
**b) Connect to an existing Postgres instance**
> β **Important:** In case the provided database is not available/ready it will spin a postgres container and use that as a fallback
```python
from testing_containers import TestingPostgres, DBConfig
dev_db_config = DBConfig(
    host="localhost",
    name="dev_db",
    user="postgres",
    password="secret",
    port=5432,
)
pg = TestingPostgres(db_config=dev_db_config)
print(pg.testdb)  # e.g. "test_dev_db" β a fresh copy created on the fly
# ... run tests ...
pg.stop()  # drops the test DB
```
β
 Each run creates a temporary database (test_<original_dbname>) and destroys it afterwards.
#### Example: using pytests, alembic and settings on conftest
- You run `TestingPostgres`
- You mock DB environment variables to the one of `TestingPostgres().postgres.test_db`
- So your app during tests runtime will be connected to **testdb**
- Create a pytest fixture which run alembic migration on start and stops testdb(drops testdb) on teardown
```python
import os
import pytest
from unittest.mock import patch
from alembic import command
from alembic.config import Config
from testing_containers import TestingPostgres
testing = TestingPostgres()
testdb = testing.postgres.test_db
env_vars = {
    "DB__USER": testdb.db.user,
    "DB__PASSWORD": testdb.db.password,
    "DB__HOST": testdb.db.host,
    "DB__PORT": str(testdb.db.port),
    "DB__NAME": testdb.db.name,
}
with patch.dict(os.environ, env_vars):
    from app.settings import settings
@pytest.fixture(scope="session", autouse=True)
def setup_test_db():
    """Setup and teardown for the test db"""
    # Run Alembic migrations
    # Ensure the path to alembic.ini is correct
    alembic_cfg = Config("alembic.ini")
    try:
        command.upgrade(alembic_cfg, "head")
    except Exception:
        raise
    yield
    testdb.stop() # Tear down test db
```
### Generic DockerContainer
Start any service container on demand β e.g. Redis:
```python
from testing_containers import DockerContainer
redis = DockerContainer(
    container_name="test-redis",
    image="redis:7",
    expose_ports=["6379:6379"]
)
redis.start_container()
result = redis.exec(["redis-cli", "ping"])
print(result.stdout.strip())  # β PONG
redis.stop_container()
redis.remove_container()
```
β
 Great for spinning up ad-hoc containers for any dependency during tests.
## π§  Why use this
| Problem | Solution |
|----------|-----------|
| π§© **Tests depend on manually started external services** | `TestingPostgres` and `DockerContainer` spin up Docker containers automatically for your tests. |
| π§Ή **Test data pollutes your development database** | Each test run uses a **fresh, isolated test database**, which is dropped when tests finish. |
| βοΈ **Local database version differs from production** | Run your tests inside Docker using the **same version** as production (e.g. `postgres:16.3`). |
| π§± **CI/CD pipelines need reproducible environments** | Works seamlessly in CI β no extra setup; containers are created and torn down automatically. |
| π **You need Redis, LocalStack, or any other service** | `DockerContainer` can run **any Docker image**, not just databases. |
| π§ͺ **You want clean, reliable integration tests** | Ensures tests always start from a **known empty state** β no shared data, no side effects. |
## π§ͺ Requirements
- Python 3.10+
- Docker (required only for containerized tests)
## π‘ Inspiration
This project was inspired by [`testing.postgresql`](https://pypi.org/project/testing.postgresql/) package,
which provides temporary PostgreSQL instances for testing.
However, `testing.postgresql` requires **PostgreSQL to be installed locally** on the developerβs machine.
That can lead to common issues in real-world teams:
- Developers might have **different PostgreSQL versions** installed.
- Local PostgreSQL configuration may **differ from the production environment**.
- Installing or managing Postgres locally can be **slow or error-prone in CI and requires additional setup**
`testing-containers` solves these problems by leveraging **Docker**:
- No local Postgres installation required.
- The same Postgres (or Redis, MariaDB, etc.) **version used in production** can be pulled and run in tests.
- Works identically on **any environment** β macOS, Linux, Windows, or CI/CD runners.
In short, it keeps the convenience of `testing.postgresql` while ensuring **environment parity and zero setup**.
## π§Ύ License
MIT Β© Tedi Cela
            
         
        Raw data
        
            {
    "_id": null,
    "home_page": "https://github.com/tedicela/testing-containers",
    "name": "testing-containers",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.10",
    "maintainer_email": null,
    "keywords": "postgresql, testing, pytest, docker, alembic",
    "author": "Tedi Cela",
    "author_email": "tedicela@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/c8/5a/59209abd4def5d6aa708131de41c0b4e3d89e2f659df8299e2287532b86c/testing_containers-0.3.1.tar.gz",
    "platform": null,
    "description": "# \ud83e\uddea testing-containers\n\n[](https://pypi.org/project/testing-containers/)\n[](https://github.com/tedicela/testing-containers/actions/workflows/ci.yml)\n[](LICENSE)\n\n> **Lightweight Python utilities for running ephemeral Docker containers in tests.**\n> Includes `TestingPostgres` for disposable PostgreSQL test databases and `DockerContainer` for ad-hoc containers.\n\n---\n\n## \ud83d\ude80 Overview\n\n`testing-containers` helps you run **real services inside Docker** for integration or functional tests \u2014 without ever needing to manually start external databases, message brokers or anything else.\n\nIt provides:\n\n- **`TestingPostgres`** \u2014 a PostgreSQL-specific helper that automatically creates a **fresh empty test database** before tests start and tears it down afterwards.\n- **`DockerContainer`** \u2014 a generic helper to start, stop, and execute commands inside *any* Docker container (Postgres, Redis, LocalStack, etc.).\n\nThe goal is simple:\n> Make your tests fully isolated, reproducible, and environment-agnostic \u2014 no shared state, no external dependencies.\n\n---\n\n## \ud83e\udded Design Principles\n\n- \ud83e\udde9 **No external services** need to be manually started\n- \ud83d\udd01 **Fresh empty databases** are created every test run\n- \ud83e\uddf9 **Automatic cleanup** when tests finish\n- \ud83e\uddf1 **No pollution of your dev DB** \u2014 tests never touch your development data\n- \u2699\ufe0f **Consistent environments** \u2014 use the same database version as production via Docker\n- \ud83e\uddf0 **Generic & extensible** \u2014 same approach works for PostgreSQL, Redis, LocalStack, RabbitMQ, etc.\n- \ud83d\udc33 **Only dependency:** Docker (required only when containers are used)\n\n---\n\n## \u2699\ufe0f Installation\n\n```bash\npip install testing-containers\n```\n\n> Requires Docker installed and running if you plan to spin up containerized services.\n\n## \ud83d\udca1 Usage\n\n### `TestingPostgres`\n\nYou can use `TestingPostgres` in two ways\n\n**a) Run Postgres inside Docker**\n\n```python\nimport psycopg\nfrom testing_containers import TestingPostgres, ContainerOptions\n\npg = TestingPostgres(\n    options=ContainerOptions(\n        namespace=\"myproject-name\" # optional \u2013 you can add a namespace to the container\n        name=\"testdb\" # optional \u2013 you can give a name to the container\n        image=\"postgres:15.6\" # optional / default postgres:16.3\n        # The following options defines what should happen on stop()\n        # container will stop or not\n        # container will be removed or not\n        # (you can decide on the speed you want on test startup and teardown)\n        should_stop=True # optional / default=False\n        remove_on_stop=True # optional / default=False\n    )\n)  # spins up a postgres:16.3 container\ntestdb = pg.postgres.testdb  # connection info for your test DB\n\n# Connect and run migrations or tests\nconn = psycopg.connect(\n    dbname=testdb.name,\n    user=testdb.user,\n    password=testdb.password,\n    host=testdb.host,\n    port=testdb.port,\n)\nprint(\"Connected:\", conn)\n\n# After tests\npg.stop()\n```\n\n**b) Connect to an existing Postgres instance**\n\n> \u2757 **Important:** In case the provided database is not available/ready it will spin a postgres container and use that as a fallback\n\n```python\nfrom testing_containers import TestingPostgres, DBConfig\n\ndev_db_config = DBConfig(\n    host=\"localhost\",\n    name=\"dev_db\",\n    user=\"postgres\",\n    password=\"secret\",\n    port=5432,\n)\npg = TestingPostgres(db_config=dev_db_config)\nprint(pg.testdb)  # e.g. \"test_dev_db\" \u2014 a fresh copy created on the fly\n# ... run tests ...\npg.stop()  # drops the test DB\n```\n\n\u2705 Each run creates a temporary database (test_<original_dbname>) and destroys it afterwards.\n\n#### Example: using pytests, alembic and settings on conftest\n\n- You run `TestingPostgres`\n- You mock DB environment variables to the one of `TestingPostgres().postgres.test_db`\n- So your app during tests runtime will be connected to **testdb**\n- Create a pytest fixture which run alembic migration on start and stops testdb(drops testdb) on teardown\n\n```python\nimport os\nimport pytest\nfrom unittest.mock import patch\nfrom alembic import command\nfrom alembic.config import Config\nfrom testing_containers import TestingPostgres\n\ntesting = TestingPostgres()\ntestdb = testing.postgres.test_db\n\nenv_vars = {\n    \"DB__USER\": testdb.db.user,\n    \"DB__PASSWORD\": testdb.db.password,\n    \"DB__HOST\": testdb.db.host,\n    \"DB__PORT\": str(testdb.db.port),\n    \"DB__NAME\": testdb.db.name,\n}\nwith patch.dict(os.environ, env_vars):\n    from app.settings import settings\n\n\n@pytest.fixture(scope=\"session\", autouse=True)\ndef setup_test_db():\n    \"\"\"Setup and teardown for the test db\"\"\"\n    # Run Alembic migrations\n    # Ensure the path to alembic.ini is correct\n    alembic_cfg = Config(\"alembic.ini\")\n    try:\n        command.upgrade(alembic_cfg, \"head\")\n    except Exception:\n        raise\n\n    yield\n\n    testdb.stop() # Tear down test db\n```\n\n\n### Generic DockerContainer\nStart any service container on demand \u2014 e.g. Redis:\n\n```python\nfrom testing_containers import DockerContainer\n\nredis = DockerContainer(\n    container_name=\"test-redis\",\n    image=\"redis:7\",\n    expose_ports=[\"6379:6379\"]\n)\n\nredis.start_container()\nresult = redis.exec([\"redis-cli\", \"ping\"])\nprint(result.stdout.strip())  # \u2192 PONG\nredis.stop_container()\nredis.remove_container()\n```\n\n\u2705 Great for spinning up ad-hoc containers for any dependency during tests.\n\n## \ud83e\udde0 Why use this\n\n| Problem | Solution |\n|----------|-----------|\n| \ud83e\udde9 **Tests depend on manually started external services** | `TestingPostgres` and `DockerContainer` spin up Docker containers automatically for your tests. |\n| \ud83e\uddf9 **Test data pollutes your development database** | Each test run uses a **fresh, isolated test database**, which is dropped when tests finish. |\n| \u2699\ufe0f **Local database version differs from production** | Run your tests inside Docker using the **same version** as production (e.g. `postgres:16.3`). |\n| \ud83e\uddf1 **CI/CD pipelines need reproducible environments** | Works seamlessly in CI \u2014 no extra setup; containers are created and torn down automatically. |\n| \ud83d\ude80 **You need Redis, LocalStack, or any other service** | `DockerContainer` can run **any Docker image**, not just databases. |\n| \ud83e\uddea **You want clean, reliable integration tests** | Ensures tests always start from a **known empty state** \u2014 no shared data, no side effects. |\n\n\n## \ud83e\uddea Requirements\n- Python 3.10+\n- Docker (required only for containerized tests)\n\n## \ud83d\udca1 Inspiration\n\nThis project was inspired by [`testing.postgresql`](https://pypi.org/project/testing.postgresql/) package,\nwhich provides temporary PostgreSQL instances for testing.\n\nHowever, `testing.postgresql` requires **PostgreSQL to be installed locally** on the developer\u2019s machine.\nThat can lead to common issues in real-world teams:\n\n- Developers might have **different PostgreSQL versions** installed.\n- Local PostgreSQL configuration may **differ from the production environment**.\n- Installing or managing Postgres locally can be **slow or error-prone in CI and requires additional setup**\n\n`testing-containers` solves these problems by leveraging **Docker**:\n- No local Postgres installation required.\n- The same Postgres (or Redis, MariaDB, etc.) **version used in production** can be pulled and run in tests.\n- Works identically on **any environment** \u2014 macOS, Linux, Windows, or CI/CD runners.\n\nIn short, it keeps the convenience of `testing.postgresql` while ensuring **environment parity and zero setup**.\n\n\n## \ud83e\uddfe License\n\nMIT \u00a9 Tedi Cela\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Spin up an isolated PostgreSQL test database (reusing local PG or Docker) with zero external service requirements for your test run.",
    "version": "0.3.1",
    "project_urls": {
        "Homepage": "https://github.com/tedicela/testing-containers",
        "Repository": "https://github.com/tedicela/testing-containers"
    },
    "split_keywords": [
        "postgresql",
        " testing",
        " pytest",
        " docker",
        " alembic"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a013c7974e457e3bf075d5e659eec1c72e05f472ce5290f32837c31c89fd26a1",
                "md5": "f18eb0d3535740fadae3533ea97648c8",
                "sha256": "a799da389178bca34e812621d9ebf45c224117f22814fee3a5c30f7af01d4702"
            },
            "downloads": -1,
            "filename": "testing_containers-0.3.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f18eb0d3535740fadae3533ea97648c8",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.10",
            "size": 10651,
            "upload_time": "2025-10-25T01:56:08",
            "upload_time_iso_8601": "2025-10-25T01:56:08.122632Z",
            "url": "https://files.pythonhosted.org/packages/a0/13/c7974e457e3bf075d5e659eec1c72e05f472ce5290f32837c31c89fd26a1/testing_containers-0.3.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c85a59209abd4def5d6aa708131de41c0b4e3d89e2f659df8299e2287532b86c",
                "md5": "86720733e74f64cb1e1925d3ebe30517",
                "sha256": "d39db8ff142eb6a820644c211ca8cbda56af5003a56db87f4267e1f2b6992d70"
            },
            "downloads": -1,
            "filename": "testing_containers-0.3.1.tar.gz",
            "has_sig": false,
            "md5_digest": "86720733e74f64cb1e1925d3ebe30517",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.10",
            "size": 11399,
            "upload_time": "2025-10-25T01:56:09",
            "upload_time_iso_8601": "2025-10-25T01:56:09.434330Z",
            "url": "https://files.pythonhosted.org/packages/c8/5a/59209abd4def5d6aa708131de41c0b4e3d89e2f659df8299e2287532b86c/testing_containers-0.3.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-25 01:56:09",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "tedicela",
    "github_project": "testing-containers",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "testing-containers"
}