pytest-django Documentation

repository·main·Indexed 23 days ago

https://github.com/pytest-dev/pytest-django

A Django plugin for the pytest testing framework that enables testing Django applications using fixtures, plugins, and parallel execution. It provides tools for configuring Django settings via environment variables, CLI flags, or configuration files, and manages database access through marks like @pytest.mark.django_db. The plugin includes features for database reuse, migration control, and integration with django-configurations.

Tokens
14.3K
Snippets
54
Records
102
Agent score
81%

What's inside pytest-django

  1. Benefits of using pytest-django over manage.py test

    main

    Using pytest-django provides several advantages over the standard Django manage.py test command:

    • Less boilerplate: Write tests as regular functions instead of subclassing unittest.TestCase.
    • Fixtures: Manage test dependencies easily using pytest fixtures.
    • Performance: Ability to run tests in multiple processes to increase speed.
    • Extensibility: Access to the vast ecosystem of pytest plugins.
    • Compatibility: Existing unittest-style tests work without modification.
  2. Advantages of using pytest-django over manage.py test

    main

    Using pytest-django instead of the standard Django manage.py test command provides several benefits by leveraging the pytest ecosystem:

    • Fixture-based dependency management: Use pytest fixtures to manage test dependencies.
    • Reduced boilerplate: Write tests as regular functions instead of requiring unittest imports or subclassing TestCase.
    • Database re-use: Avoid the overhead of re-creating the test database for every single test run.
    • Parallel execution: Speed up your test suite by running tests in multiple processes using the pytest-xdist plugin.
    • Plugin ecosystem: Access the wide range of existing pytest plugins.
    • Backward compatibility: Existing unittest-style TestCase classes continue to work without modification.
  3. Customize database configuration via fixtures

    main
    pytest-django allows you to customize the database setup process by overriding specific fixtures in your conftest.py. These fixtures can be used to influence how databases are created, configured, or modified. To override a fixture, define a new fixture with the same name and scope in your conftest.py.
  4. Precedence of Django settings configuration

    main

    When multiple configuration methods are used, pytest-django resolves the settings module based on the following order of precedence (from highest to lowest):

    1. The command line option --ds=SETTINGS
    2. The environment variable DJANGO_SETTINGS_MODULE
    3. The DJANGO_SETTINGS_MODULE option in configuration files (pytest.ini, tox.ini, or pyproject.toml).

    To force the configuration file to use the highest precedence, you can use addopts = --ds=yourtestsettings in your pytest configuration.

  5. How pytest-django finds Django projects automatically

    main

    By default, pytest-django attempts to locate your Django project by searching for a manage.py file. It starts from the current test root directory and searches upwards through parent directories until it finds the first manage.py. Once found, the directory containing manage.py is automatically added to the Python path.

    If you have a non-standard project structure, multiple manage.py files, or no manage.py file at all, this automatic detection might fail or point to the wrong directory. In these cases, you should disable automatic detection and manage the Python path explicitly.

  6. Automatic cleanup of Site cache and mail.outbox

    main

    To ensure a clean and consistent testing environment, pytest-django performs automatic cleanup for certain Django components:

    • Site cache: If django.contrib.sites is included in your INSTALLED_APPS, the Site cache is cleared for every test. This prevents Site.objects.get_current() from returning incorrect objects due to stale cache data.
    • mail.outbox: The mail.outbox is cleared for each pytest run to provide an empty mailbox. However, for a more idiomatic pytest approach, it is recommended to use the mailoutbox fixture instead of accessing mail.outbox directly.
  7. Basic usage of pytest-django

    main

    When using pytest-django, you do not use django-admin.py or manage.py to run tests. Instead, you invoke the pytest command directly. This allows you to use all standard pytest options and plugins.

    To run the entire test suite in the current directory, simply run: pytest

    To run specific test files or directories, pass them as arguments: pytest test_something.py a_directory

    pytest
    
    pytest test_something.py a_directory
  8. Run tests in parallel with pytest-xdist

    main

    To speed up test execution on multi-core/multi-CPU machines, you can use the pytest-xdist plugin.

    1. Install the plugin: pip install pytest-xdist

    2. Run tests with a specified number of processes using the -n flag: pytest -n <number of processes>

    Database Handling: When using xdist, pytest-django creates a separate test database for each process. Databases are suffixed with the process identifier (e.g., gw0, gw1). For example, if your database name is foo, the parallel test databases will be test_foo_gw0, test_foo_gw1, etc.

  9. Guidelines for contributing documentation

    main

    Documentation is written using Sphinx and reStructuredText (.rst files). When contributing documentation, follow these principles:

    • Language: All documentation must be written in English.
    • Format: Use .rst files.
    • Accessibility: Assume readers are moderately familiar with Python and Django, but provide context or links for other libraries used (e.g., linking to external library documentation).
    • Style: Focus on clarity and accessibility rather than strict stylistic perfection.
  10. Modify apps before Django setup via pytest plugin

    main

    Because pytest-django calls django.setup() automatically, any modifications to your apps (like patching signals) must occur before this call. To achieve this, create a pytest plugin and implement the pytest_load_initial_conftests hook with tryfirst=True.

    ```python
    # Example plugin implementation
    @pytest.hookimpl(tryfirst=True)
    def pytest_load_initial_conftests(early_config, parser, args):
        import project.app.signals
    
        def noop(*args, **kwargs):
            pass
    
        project.app.signals.something = noop

    To use this plugin, add it to your addopts in your configuration file using the -p flag (e.g., addopts = -p my_plugin_name).