Test containers help you run real services like databases in Docker during tests. This makes tests more reliable and close to real use.
Test containers with Docker in PyTest
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
PyTest
from testcontainers.postgres import PostgresContainer import pytest from sqlalchemy import create_engine @pytest.fixture(scope='module') def postgres_container(): with PostgresContainer('postgres:15') as postgres: yield postgres def test_database_connection(postgres_container): engine = create_engine(postgres_container.get_connection_url()) # Your test code here
Use with PostgresContainer('image') to start and stop the container automatically.
Use pytest fixtures to manage container lifecycle during tests.
Examples
PyTest
from testcontainers.redis import RedisContainer with RedisContainer('redis:7') as redis: redis_url = redis.get_connection_url() # Connect your app to redis_url
PyTest
import pytest from testcontainers.mysql import MySqlContainer @pytest.fixture(scope='function') def mysql_container(): with MySqlContainer('mysql:8') as mysql: yield mysql
Sample Program
This test starts a Postgres container, creates a table, inserts data, and queries it to check correctness.
PyTest
from testcontainers.postgres import PostgresContainer from sqlalchemy import create_engine, text import pytest @pytest.fixture(scope='module') def postgres_container(): with PostgresContainer('postgres:15') as postgres: yield postgres def test_insert_and_query(postgres_container): engine = create_engine(postgres_container.get_connection_url()) with engine.connect() as conn: conn.execute(text('CREATE TABLE test (id INT PRIMARY KEY, name VARCHAR(50));')) conn.execute(text("INSERT INTO test (id, name) VALUES (1, 'Alice');")) conn.commit() result = conn.execute(text('SELECT name FROM test WHERE id=1;')) name = result.scalar() assert name == 'Alice' print(f'Queried name: {name}')
Important Notes
Make sure Docker is running before you run tests using test containers.
Test containers automatically clean up after tests, so no leftover services remain.
Use lightweight official images to keep tests fast.
Summary
Test containers let you run real services in Docker during tests.
Use pytest fixtures to manage container lifecycle easily.
This approach makes tests more reliable and closer to real-world use.
Practice
1. What is the main benefit of using test containers with Docker in pytest?
easy
Solution
Step 1: Understand test containers purpose
Test containers run real services like databases inside Docker during tests.Step 2: Identify benefit in pytest context
This makes tests more reliable and realistic by using actual service environments.Final Answer:
They provide real service environments during tests for better reliability. -> Option DQuick Check:
Real service environment = Better test reliability [OK]
Hint: Remember: test containers run real services inside Docker [OK]
Common Mistakes:
- Thinking test containers replace writing tests
- Believing they fix code bugs automatically
- Assuming tests run faster by skipping setup
2. Which pytest fixture code correctly starts a Docker container for testing?
easy
Solution
Step 1: Check correct Docker client usage
Use docker.from_env() to get client, then client.containers.run() with detach=True to start container.Step 2: Verify fixture lifecycle management
Yield container for test, then stop container after test finishes.Final Answer:
def container(): client = docker.from_env() container = client.containers.run('redis', detach=True) yield container container.stop() -> Option CQuick Check:
Use client.containers.run with detach=True [OK]
Hint: Use client.containers.run with detach=True to start container [OK]
Common Mistakes:
- Calling client.run instead of client.containers.run
- Missing detach=True causing blocking call
- Not stopping container after test
3. Given this pytest fixture, what will be printed when running the test?
import pytest
import docker
@pytest.fixture
def redis_container():
client = docker.from_env()
container = client.containers.run('redis:alpine', detach=True)
yield container
container.stop()
def test_redis_running(redis_container):
print(redis_container.status)medium
Solution
Step 1: Understand container lifecycle in fixture
Container is started with detach=True, so status should be 'running' during test.Step 2: Check printed status in test
redis_container.status returns current container status, expected 'running' while test runs.Final Answer:
running -> Option AQuick Check:
Container started = status 'running' [OK]
Hint: Container status is 'running' while test uses it [OK]
Common Mistakes:
- Expecting 'created' before container starts
- Assuming container is 'exited' during test
- Confusing status with container image tag
4. Identify the error in this pytest fixture that manages a Docker container:
@pytest.fixture
def redis_container():
client = docker.from_env()
container = client.containers.run('redis', detach=True)
yield container
container.remove()medium
Solution
Step 1: Check container cleanup steps
Container must be stopped before removal to avoid errors.Step 2: Identify missing stop call
Fixture calls container.remove() but misses container.stop() before it.Final Answer:
Missing container.stop() before container.remove() to stop container properly. -> Option AQuick Check:
Stop container before remove to clean up [OK]
Hint: Always stop container before removing it [OK]
Common Mistakes:
- Calling remove without stopping container
- Confusing remove() with non-existent delete()
- Assuming environment vars are mandatory for container start
5. You want to write a pytest fixture that starts a PostgreSQL container with Docker, waits until it is ready to accept connections, and then yields it for tests. Which approach correctly combines container management and readiness check?
hard
Solution
Step 1: Manage container lifecycle properly
Start PostgreSQL container detached to run in background during tests.Step 2: Implement readiness check before yielding
Poll container logs for 'database system is ready' message to ensure service is ready.Step 3: Yield container after readiness confirmed
This ensures tests run only after PostgreSQL is ready to accept connections.Final Answer:
Start container with detach=True, then poll container logs until 'database system is ready' appears before yielding. -> Option BQuick Check:
Wait for readiness log before yielding container [OK]
Hint: Wait for readiness log, don't guess with sleep [OK]
Common Mistakes:
- Yielding container before it is ready
- Using fixed sleep instead of log polling
- Starting container without detach causing blocking
