Pytest & it's plugin architecture

Posted on May 4, 2023

pytest is a popular Python testing framework that provides a flexible and extensible way to write tests for your code. One of the key strengths of pytest is its plugin architecture, which allows you to customize and extend the behavior of the framework to meet your specific needs.

One such plugin is pytest-django, which provides support for testing Django applications with pytest. In this blog post, we’ll take a closer look at the plugin architecture of pytest and pytest-django and explore how plugins can be used to customize and enhance the testing process.

Plugin Architecture

At its core, pytest is a collection of hooks, fixtures, and plugins that work together to define the testing process. Hooks are functions that are called at specific points during the testing process, such as before or after a test is run. Fixtures are functions that provide reusable test data and resources, such as database connections or mock objects. Plugins are collections of hooks and fixtures that provide additional functionality to pytest.

Plugins can be distributed as standalone packages, or they can be included as part of a larger project. When pytest starts up, it searches for available plugins and loads them into memory. Each plugin defines a set of hooks and fixtures that pytest can use to customize the testing process.

pytest-django Plugin

pytest-django is a powerful plugin for pytest that provides support for testing Django applications. It includes a number of helpful fixtures and utilities that make it easy to write tests for Django models, views, and other components.

One of the key features of pytest-django is its support for automatically setting up and tearing down a test database. This allows you to write tests that interact with the database without affecting your development database, and ensures that each test runs in a clean and isolated environment.

To use pytest-django, you simply need to install it and include it in your pytest configuration:

pip install pytest-django
# pytest.ini
[pytest]
DJANGO_SETTINGS_MODULE = myproject.settings

Now you can use the pytest-django fixtures and utilities in your tests to write powerful and flexible tests for your Django applications.

How pytest-django works under the hood

When running pytest command, it collects all test modules (files that have test functions) and their associated test functions. pytest-django provides hooks that are called before and after each test module, test class, or test function to set up a Django test environment, which is isolated from the main Django application.

For example, the django_db_setup fixture sets up a test database that is used to store data during tests. When pytest detects a test function that uses the django_db_setup fixture, it sets up a test database using the settings specified in the Django project’s settings file. It creates a new test database for each test function, and applies any necessary database migrations. This ensures that each test function has a clean slate and no data is shared between them.

pytest-django also provides several other fixtures that make it easier to test Django applications. The client fixture provides a test client that can be used to simulate HTTP requests to a Django view function. The live_server fixture starts a live Django server that can be used to test end-to-end scenarios. The admin_client fixture provides an authenticated client for the Django admin site.

In addition to fixtures, pytest-django also provides hooks that allow developers to customize the behavior of the test environment. For example, the django_test_environment hook allows developers to customize the settings of the test environment. The django_assert_num_queries hook allows developers to assert that a test function makes a specific number of database queries.

Under the hood, pytest-django uses the setup_test_environment() function provided by Django to set up a test environment. This function patches various components of the Django framework to ensure that tests run correctly in a test environment. pytest-django also provides a fixture called django_testdir that allows developers to create a temporary Django project with the desired structure for testing.

In summary, pytest-django leverages the pytest plugin architecture to provide a comprehensive suite of fixtures and hooks that make it easy to test Django applications. It provides a clean and isolated environment for each test function, ensuring that no data is shared between tests. With its rich set of features and easy-to-use fixtures, pytest-django is a powerful tool for testing Django applications.