Skip to main content

A pytest plugin that cleans your database up after every test.

Project description

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_clean_database-1.0.0.tar.gz (6.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_clean_database-1.0.0-py3-none-any.whl (8.6 kB view details)

Uploaded Python 3

File details

Details for the file pytest_clean_database-1.0.0.tar.gz.

File metadata

  • Download URL: pytest_clean_database-1.0.0.tar.gz
  • Upload date:
  • Size: 6.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.1 CPython/3.12.3 Linux/6.8.0-1021-azure

File hashes

Hashes for pytest_clean_database-1.0.0.tar.gz
Algorithm Hash digest
SHA256 a61b9aaedc07084e32dc2793b641d3f34a1a21371fa09610e28bbbd3ce4b8db2
MD5 a97ae6a06dbd87efc597807c3ec9be77
BLAKE2b-256 58791ce7f9f7635dd234de7ee2673b42f84a6fa8b2588a30099521ac9760f9f3

See more details on using hashes here.

File details

Details for the file pytest_clean_database-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_clean_database-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6ba8e00fd4eb4ed060bfb2dd62346103dfccedc2b35672d32999a58611145893
MD5 dfaffc958ef134d8c20f2ee27d8e7645
BLAKE2b-256 f3df14f79d32a75b7e14b56115b14d762732012348259a24a95af904e8efff1b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page