pytest-docker

Pytest fixtures that spin up Docker Compose services for integration tests, then tear them down automatically.

Tool
PyPI
v3.2.5
489stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
41/100Fair
Development Activity0
Maintenance20
Community64
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
69/100Good
Architecture72
Code Quality80
Innovation68
Learning Curve55

pytest-docker is a small pytest plugin that turns a docker-compose.yml file into a set of ready-to-use fixtures for integration testing. Point it at your compose file and it will bring the defined services up before your tests run, wait for them to report healthy via --wait (or a custom readiness check you write), hand your tests the resolved host/port for each container, and tear everything down again once the session ends.

It was built for the common case where an integration test suite needs a real database, cache, or HTTP service running in Docker rather than a mock. Instead of hand-rolling subprocess calls to docker compose in a conftest.py, teams install the plugin, register it as a pytest11 entry point (automatic once installed), and override a handful of well-named fixtures — docker_compose_file, docker_compose_project_name, docker_setup, docker_cleanup — only where the defaults don’t fit. It supports both Docker Compose V2 (docker compose, the default) and the deprecated V1 docker-compose binary via an extra.

What You Get

  • A docker_services fixture that runs docker compose up --build --wait before the session and docker compose down -v after it, scoped by default to the whole test session
  • A docker_ip fixture that resolves the correct host address for reaching containers, accounting for remote DOCKER_HOST setups
  • port_for(service, container_port) to look up the host-mapped port for any service/port pair defined in the compose file, with an internal cache so repeated calls are free
  • wait_until_responsive(check, timeout, pause) to poll a custom readiness callable until a service accepts connections or the timeout is hit
  • A --container-scope CLI flag plus a container_scope_fixture so fixture scope (session/module/class) is configurable without editing test code
  • Override points (docker_compose_file, docker_compose_project_name, docker_setup, docker_cleanup, docker_compose_command) so any part of the compose lifecycle can be customized in conftest.py

Common Use Cases

  • Running integration tests against a real Postgres/Redis/HTTP service defined in a project’s docker-compose.yml without a separate CI script to manage the stack
  • Verifying an HTTP service is actually reachable before tests hit it, using wait_until_responsive together with a plain requests.get health check
  • Pinning a fixed compose project name so a test suite re-run from an IDE tears down a stale stack before starting a fresh one, instead of accumulating duplicate containers
  • Composing multiple compose files (e.g. a base stack plus a test-specific override) by returning a list of paths from the docker_compose_file fixture
  • Supporting teams still on Docker Compose V1 by swapping the docker_compose_command fixture to docker-compose and installing the docker-compose-v1 extra

Under The Hood

Architecture The plugin is a single module (src/pytest_docker/plugin.py) re-exported through __init__.py, which also registers the --container-scope CLI option via pytest_addoption and is wired up as a pytest11 entry point in setup.cfg so pytest auto-loads it on install. The core lifecycle lives in get_docker_services, a contextlib.contextmanager that builds a frozen DockerComposeExecutor (an attrs-based value object wrapping the compose command, file list, and project name), runs the configured docker_setup commands, yields a frozen Services object for the test session, and always runs docker_cleanup commands in a finally block regardless of test outcome. Every configurable piece — command, compose file(s), project name, setup/cleanup commands — is its own small pytest fixture, so overriding one behavior in a conftest.py doesn’t require touching the plugin’s internals; this fixture-per-concern layering is the one thing that would need to change if the compose invocation model itself changed.

Tech Stack Pure Python 3.8+, packaged with legacy setuptools/setup.cfg metadata behind a minimal pyproject.toml build-system declaration. Runtime dependencies are deliberately tiny: pytest (>=4.0,<10.0) for the fixture/plugin machinery and attrs (>=19.2.0) for immutable value objects (Services, DockerComposeExecutor). An optional docker-compose-v1 extra pins the legacy docker-compose CLI for teams not yet on Compose V2. Shelling out to docker compose/docker-compose itself happens via subprocess.check_output, not a Docker SDK. CI runs on GitHub Actions with a separate publish workflow for PyPI releases.

Code Quality The test suite (tests/) mixes direct fixture-value assertions (e.g. asserting docker_compose_command resolves to "docker compose") with pytest’s own pytester/testdir fixtures to run the plugin against synthetic test files it generates on the fly, letting the suite exercise real fixture-scope behavior (--container-scope=session|module|class) end to end rather than just unit-testing helper functions. plugin.py carries type hints throughout (Dict, Union, Optional, Iterator) and the project enforces mypy --strict, pylint, and pycodestyle as pytest plugins invoked via addopts in setup.cfg, so a normal pytest run doubles as the lint/type gate; all three are also wired into CI. No dedicated docs/ folder or CONTRIBUTING file exists — the README carries setup, override, and contribution guidance in one document.

API Design The public surface is deliberately small and idiomatic to pytest: five fixtures plus a Services helper class, all overridable using pytest’s normal fixture-shadowing convention rather than a bespoke plugin-configuration format. Sensible defaults (docker compose, tests/docker-compose.yml, session scope, up --build --wait/down -v) mean a project with a compose file already in the conventional location needs zero configuration to get a working docker_services fixture; less common needs (multiple compose files, V1 compose, custom project naming to avoid stale-stack collisions) are each a one-fixture override documented directly in the README with a runnable snippet.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search