Skip to main content

pytest-clean-database

Ruff PyPI - Version PyPI - Python Version PyPI - Downloads

A pytest plugin that provides a clear and concise way to help you keep your test database clean between tests, maintaining a proper test isolation.

Installation

pytest-clean-database requires Python >=3.8 and pytest >=7.0.

There is support for two databases, PostgreSQL and MySQL.

To install with support for PostgreSQL (using Psycopg3):

pip install pytest-clean-database[psql]

To install with support for MySQL (using PyMySQL):

pip install pytest-clean-database[mysql]

Or both:

pip install pytest-clean-database[psql,mysql]

Usage

In your conftest.py сreate a new fixture called clean_db_urls and make it return a sequence of database connection strings (in other words, DSNs) for every PostgreSQL/MySQL test database you're using during the test run.

Use postgresql:// scheme for PostgreSQL and mysql:// scheme for MySQL.

IMPORTANT! Make sure that clean_db_urls requires the fixture responsible for creating your test database and running migrations on it. See Mode of operation for an explanation.

Example:

# conftest.py

@pytest.fixture()
def test_db():
    create_database()
    run_migrations()
    
    yield 
    
    drop_database()
    
@pytest.fixture(scope="session")
def clean_db_urls(test_db):  # Require test_db fixture.
    return [
        "postgresql://username:password@localhost:5432/test", 
        "mysql://username:password@localhost:3306/test"
    ]

PostgreSQL note: by default, public schema will be used. To change the schema, you can pass it via --clean-db-pg-schema argument to pytest.

There's an example project that showcases the usage of the package.

Mode of operation

Simply put, the approach for this package is to keep track of changes made to tables using database triggers and an internal table, and truncate only the dirty ones. This way we do not waste time truncating every table.

There are two steps to the machinery, implemented as session-scoped autouse fixtures.

  1. Set up all database objects that we need - executed only once at the start of the test session.
    1. Create an internal table that keeps track of user tables and their dirtyness.
    2. Create a function that sets the dirty state for a given table.
    3. Create a function that iterates over dirty tables and truncates them, then resets the dirty state.
    4. For every user table, create an INSERT trigger that will execute the function that marks this table as dirty.
  2. Clean database tables - executed after every test.

For this to work properly it's important to execute the setup step only after the user tables have been created - otherwise, we won't be able to track their dirtyness. This also implies that if you create a table inside a test - it won't be tracked either. Luckily, pytest fixtures have this incredible feature, where one fixture can request another one, forming a dependency graph.

When you expose your DSNs via clean_db_urls fixture, pytest-clean-database's setup fixture requests this fixture. This way you get to decide when the setup happens. And this is why you must ensure that your clean_db_urls fixture requests the fixture that sets up your test database. If you set up your test database in some way other than pytest fixtures, it still should be possible to create a fixture that blocks until your test database is ready.

Rationale

When you develop an application that makes use of a database, most likely you will end up having at least a few test cases that somehow operate on your test database, creating side effects (like inserting and updating rows). That means, to keep your tests properly isolated from each other you have to undo the side effects made during the previous test, and start your next test with a blank slate.

Some frameworks provide users with means to do that: for example, Django takes care of keeping your test database fresh and clean, so you don't have to worry about it. But if you're using, say, FastAPI and SQLAlchemy, or even Blacksheep and asyncpg (a database driver), you are on your own to create the solution to this problem.

The solution might be as simple as recreating the test database for every test, but as the size of the test suite grows, this will become slower. TRUNCATE TABLE ... improves the performance a bit, but if you have tens and hundreds of tables, truncating every one of them on every test still will be unacceptably slow.

Hence, this plugin.

Metadata

Release files for pytest-clean-database 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytest-clean-database 1.0.0
File Size Uploaded
pytest_clean_database-1.0.0.tar.gz 6.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pytest-clean-database 1.0.0
File Interpreter ABI Platform
pytest_clean_database-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 14.8 kB

Release files / pytest_clean_database-1.0.0.tar.gz

Download URL pytest_clean_database-1.0.0.tar.gz
Size 6.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a61b9aaedc07084e32dc2793b641d3f34a1a21371fa09610e28bbbd3ce4b8db2
BLAKE2b-256 checksum
How to use checksums
58791ce7f9f7635dd234de7ee2673b42f84a6fa8b2588a30099521ac9760f9f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.1 CPython/3.12.3 Linux/6.8.0-1021-azure

Release files / pytest_clean_database-1.0.0-py3-none-any.whl

Download URL pytest_clean_database-1.0.0-py3-none-any.whl
Size 8.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6ba8e00fd4eb4ed060bfb2dd62346103dfccedc2b35672d32999a58611145893
BLAKE2b-256 checksum
How to use checksums
f3df14f79d32a75b7e14b56115b14d762732012348259a24a95af904e8efff1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.1 CPython/3.12.3 Linux/6.8.0-1021-azure

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page