from pytest_postgresql import factories
# Create a custom process fixture
postgresql_my_proc = factories.postgresql_proc(
port=None, unixsocketdir='/var/run')
# Create a client fixture that uses the custom process
postgresql_my = factories.postgresql('postgresql_my_proc')
# Async client fixture (requires pytest-postgresql[async], pytest-asyncio >= 1.4)
postgresql_my_async = factories.postgresql_async('postgresql_my_proc')
Pre-populating the database for tests
If you want the database to be automatically pre-populated with your schema and data, there are two levels you can achieve it:
- Per test: In a client fixture, by using an intermediary fixture.
- Per session: In a process fixture.
The process fixture accepts a load parameter, which supports:
- SQL file paths: Loads and executes the SQL files.
- Loading functions: A callable or an import string (e.g.,
"path.to.module:function").
These functions receive host, port, user, dbname, and password and must perform the connection themselves (or use an ORM).
The process fixture pre-populates the database once per session into a template database. The client fixture then clones this template for each test, which significantly speeds up your tests.
from pathlib import Path
postgresql_my_proc = factories.postgresql_proc(
load=[
Path("schemafile.sql"),
"import.path.to.function",
load_this_callable
]
)
Defining pre-population on the command line:
pytest --postgresql-load=path/to/file.sql --postgresql-load=path.to.function
If a loaded .sql file contains statements that cannot run inside a transaction
block (for example CREATE DATABASE), enable autocommit on the loader connection.
This can be set without writing a custom loader, via the factory argument, the command
line, or pytest.ini:
postgresql_my_proc = factories.postgresql_proc(load=[Path("with_create_db.sql")], load_autocommit=True)
pytest --postgresql-load-autocommit
Connecting to an existing PostgreSQL database
To connect to an external server (e.g., running in Docker), use the postgresql_noproc fixture.
For async tests against an external server, create a client fixture with
factories.postgresql_async("postgresql_noproc") (see
tests/examples/test_drop_test_database_async.py).
postgresql_external = factories.postgresql('postgresql_noproc')
By default, it connects to 127.0.0.1:5432.
Using a maintenance database other than postgres
Creating and dropping the test databases requires a connection to a database that already
exists - by default postgres. If the test role merely lacks the privilege,
GRANT CONNECT ON DATABASE postgres TO myuser is the simpler fix. When postgres is
not reachable at all - behind a connection pooler with a fixed database list, or on a
managed server that does not expose it - point the noproc fixture at another database:
pytest --postgresql-maintenance-dbname=my_existing_db
postgresql_external = factories.postgresql_noproc(maintenance_dbname="my_existing_db")
The database is only connected to, never created, modified or dropped. Avoid template1:
CREATE DATABASE clones it when no template is given, and PostgreSQL does not expect the
source database to be in use while it is being copied.
Chaining fixtures
You can chain multiple postgresql_noproc fixtures to layer your data pre-population. Each fixture in the chain will create its own template database based on the previous one.
from pytest_postgresql import factories
# 1. Start with a process or a no-process base
base_proc = factories.postgresql_proc(load=[load_schema])
# 2. Add a layer with some data
seeded_noproc = factories.postgresql_noproc(depends_on="base_proc", load=[load_data])
# 3. Add another layer with more data
more_seeded_noproc = factories.postgresql_noproc(depends_on="seeded_noproc", load=[load_more_data])
# 4. Use the final layer in your test
client = factories.postgresql("more_seeded_noproc")

Configuration
You can define settings via fixture factory arguments, command line options, or pytest.ini. They are resolved in this order:
Fixture factory argument
Command line option
pytest.ini configuration option
Configuration options
| Setting |
postgresql_proc argument |
postgresql_noproc argument |
Command line option |
pytest.ini option |
Default |
| Path to executable |
executable |
n/a |
--postgresql-exec |
postgresql_exec |
discovered (see note) |
| host |
host |
host |
--postgresql-host |
postgresql_host |
127.0.0.1 |
| port |
port |
port |
--postgresql-port |
postgresql_port |
random (proc), 5432 (noproc) |
| Port search count |
— |
n/a |
--postgresql-port-search-count |
postgresql_port_search_count |
5 |
| postgresql user |
user |
user |
--postgresql-user |
postgresql_user |
postgres |
| password |
password |
password |
--postgresql-password |
postgresql_password |
|
| Starting parameters (extra pg_ctl arguments) |
startparams |
n/a |
--postgresql-startparams |
postgresql_startparams |
-w |
| Postgres exe extra arguments (passed via pg_ctl's -o argument) |
postgres_options |
n/a |
--postgresql-postgres-options |
postgresql_postgres_options |
|
| Location for unixsockets |
unixsocket |
n/a |
--postgresql-unixsocketdir |
postgresql_unixsocketdir |
$TMPDIR |
| Database name |
dbname |
dbname (handles xdist) |
--postgresql-dbname |
postgresql_dbname |
tests |
| Maintenance database name |
n/a |
maintenance_dbname |
--postgresql-maintenance-dbname |
postgresql_maintenance_dbname |
postgres |
| Default Schema (load list) |
load |
load |
--postgresql-load |
postgresql_load |
|
| Autocommit for the SQL loader connection |
load_autocommit |
load_autocommit |
--postgresql-load-autocommit |
postgresql_load_autocommit |
False |
| PostgreSQL connection options |
options |
options |
--postgresql-options |
postgresql_options |
|
| Drop test database on start |
— |
— |
--postgresql-drop-test-database |
|
false |
| Fixture to layer the template database on |
n/a |
depends_on |
|
|
|
— means the setting applies to that fixture but has no factory argument;
n/a means the setting does not apply to that fixture at all.
Note
If the executable factory argument is not provided, the plugin looks for pg_ctl in
this order:
- the configured path (
--postgresql-exec / the postgresql_exec ini option;
on Unix this defaults to /usr/lib/postgresql/14/bin/pg_ctl, on Windows there is no
default path),
- the directory reported by
pg_config --bindir,
- on Windows,
%ProgramFiles%\PostgreSQL\*\bin\pg_ctl.exe (newest version first),
pg_ctl on PATH (via shutil.which).
Only the executable factory argument is taken at face value; the other locations are
verified to exist before being used. If none of them is there, an ExecutableMissingException
is raised listing the locations that were checked.
Note
postgresql_proc starts and manages a PostgreSQL server for you, so it needs the
PostgreSQL server installed locally. Installing only the client libraries
(libpq-dev on Debian/Ubuntu) provides pg_config but no pg_ctl, and the plugin
will refuse to start. To test against a server you run yourself — a dockerised one, for
instance — use the postgresql_noproc fixture instead.
Examples
Using SQLAlchemy
This example shows how to create an SQLAlchemy session fixture:
from typing import Iterator
import pytest
from psycopg import Connection
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker, scoped_session
from sqlalchemy.pool import NullPool
@pytest.fixture
def db_session(postgresql: Connection) -> Iterator[Session]:
"""Session for SQLAlchemy."""
user = postgresql.info.user
host = postgresql.info.host
port = postgresql.info.port
dbname = postgresql.info.dbname
connection_str = f'postgresql+psycopg://{user}:@{host}:{port}/{dbname}'
engine = create_engine(connection_str, echo=False, poolclass=NullPool)
# Assuming you use a Base model
from my_app.models import Base
Base.metadata.create_all(engine)
SessionLocal = scoped_session(sessionmaker(bind=engine))
yield SessionLocal()
SessionLocal.close()
Base.metadata.drop_all(engine)
Advanced Usage: DatabaseJanitor
DatabaseJanitor is an advanced API for managing database state outside of standard fixtures. It is used by projects like Warehouse (pypi.org).
import psycopg
from pytest_postgresql.janitor import DatabaseJanitor
def test_manual_janitor(postgresql_proc):
with DatabaseJanitor(
user=postgresql_proc.user,
host=postgresql_proc.host,
port=postgresql_proc.port,
dbname="my_custom_db",
password="secret_password",
):
with psycopg.connect(
dbname="my_custom_db",
user=postgresql_proc.user,
host=postgresql_proc.host,
port=postgresql_proc.port,
password="secret_password",
) as conn:
# use connection
pass
Advanced Usage: AsyncDatabaseJanitor
AsyncDatabaseJanitor is the async counterpart to DatabaseJanitor. Use it
when managing database state with psycopg.AsyncConnection outside of standard
fixtures. It requires psycopg (a core dependency). Install
pytest-postgresql[async] when you need aiofiles for SQL file loading via
sql_async, or pytest-asyncio for pytest async tests.
import pytest
import psycopg
from pytest_postgresql.janitor import AsyncDatabaseJanitor
@pytest.mark.asyncio
async def test_manual_async_janitor(postgresql_proc):
async with AsyncDatabaseJanitor(
user=postgresql_proc.user,
host=postgresql_proc.host,
port=postgresql_proc.port,
dbname="my_custom_db",
password="secret_password",
):
async with await psycopg.AsyncConnection.connect(
dbname="my_custom_db",
user=postgresql_proc.user,
host=postgresql_proc.host,
port=postgresql_proc.port,
password="secret_password",
) as conn:
# use async connection
pass
Connecting to PostgreSQL in Docker
To connect to a Docker-run PostgreSQL, use the noproc fixture.
docker run --name some-postgres -e POSTGRES_PASSWORD=mysecret -d postgres
In your tests:
from pytest_postgresql import factories
postgresql_in_docker = factories.postgresql_noproc()
postgresql = factories.postgresql("postgresql_in_docker", dbname="test")
def test_docker(postgresql):
with postgresql.cursor() as cur:
cur.execute("SELECT 1")
Run with:
pytest --postgresql-host=172.17.0.2 --postgresql-password=mysecret
Basic database state for all tests
You can define a load function and pass it to your process fixture factory:
import psycopg
from pytest_postgresql import factories
def load_database(**kwargs):
with psycopg.connect(**kwargs) as conn:
with conn.cursor() as cur:
cur.execute("CREATE TABLE stories (id serial PRIMARY KEY, name varchar);")
cur.execute("INSERT INTO stories (name) VALUES ('Silmarillion'), ('The Expanse');")
postgresql_proc = factories.postgresql_proc(load=[load_database])
postgresql = factories.postgresql("postgresql_proc")
def test_stories(postgresql):
with postgresql.cursor() as cur:
cur.execute("SELECT count(*) FROM stories")
assert cur.fetchone()[0] == 2
The process fixture populates the template database once, and the client fixture clones it for every test. This is fast, clean, and ensures no dangling transactions. This approach works with both postgresql_proc and postgresql_noproc.
GitHub で README を読む(新しいタブで開きます)