Reformulated Message

Practical guide to testing in Django and pytest: Makefile for parallelism, safe and isolated fixtures, xdist and testmon, IDE integration, and TDD best practices.

sábado, 16 de agosto de 2025 • 4 min read • Q2BSTUDIO Team

Artificial-Intelligence-

In this article I explain best practices for running and debugging tests in Django and pytest projects, translating and adapting practical examples about Makefile, fixtures, and test acceleration tools such as pytest xdist and pytest testmon.

Example of a Makefile to launch tests with parallelism and markers: manage equals poetry run python src/manage.py SIMULTANEOUS_TEST_JOBS equals 4 and the test task runs cd src and then poetry run pytest -n ${SIMULTANEOUS_TEST_JOBS} -m not single_thread. With this command, make test runs the tests in parallel in 4 processes or threads depending on the project configuration.

To make the most of resources, you can use SIMULTANEOUS_TEST_JOBS equals auto so that pytest xdist detects the best level of concurrency. Another useful option is to add the --ff flag to first repeat the tests that failed in the last run and --testmon to run only the tests affected by code changes.

A more advanced Makefile can include testmon as a specific task that runs cd src and poetry run pytest -n ${SIMULTANEOUS_TEST_JOBS} --ff --testmon -x -l. The -x option stops execution after the first failure and the -l option shows long traces with additional failure information.

pytest testmon saves its state in cache and that file must be added to the repository's .gitignore to avoid conflicts between branches and environments. Running pytest with --testmon speeds up development iterations because only the tests affected by recent changes are re-run.

A typical error when writing tests is causing side effects from shared fixtures. For example, a test that patches get_current_user to return None can cause an AttributeError later if the object passed to the function under test is None or if there was a name collision with another fixture called paid_order.

If a call to refund receives paid_order and then tries to access paid_order.price, and paid_order turns out to be None due to an error in the test setup, an AttributeError occurs. To avoid this, you must review the definition of fixtures in the same module and in conftest.py and ensure that mutable objects are not overwritten or reused between tests.

Best practices for Django and pytest fixtures: 1 place common and reusable fixtures in conftest.py so they are available throughout the package, 2 avoid modifying instead of creating new instances within secondary fixtures, and 3 when you need a variation of a base fixture, create a new fixture that creates its own independent object to avoid side effects between tests.

Example of a bad approach that causes interdependence: the user fixture creates a user with is_staff True and then inside a class a user fixture modifies the same instance to change last_login or is_staff. This causes other tests to receive the modified object. Instead, create user_no_staff that creates a new user with is_staff False or clone the entity without sharing the same instance in memory.

Options for cloning or isolating objects in fixtures: get a new instance with User.objects.get id equal to the original id and then assign id None before saving, or simply User.objects.create with the necessary values. The second option is usually clearer and avoids identity subtleties in the Django ORM.

Tips for organizing tests in Django with pytest: use conftest.py for shared fixtures, name fixtures clearly to avoid collisions, document complex fixtures, and prefer fixtures that return new objects instead of mutating existing ones. This facilitates the use of tools like pytest -k and pytest -m and integration with IDEs.

Integration with IDEs like PyCharm: configure PyCharm to use pytest as the test runner and ensure that the virtual interpreter and environment variables match those used by poetry or pipenv. This avoids the IDE running a different environment and reduces the risk of tests that pass in the console but fail in the IDE.

Note on TDD: writing tests first forces you to design more modular and testable code and reduces the risk of hidden dependencies between components. Adopting TDD helps prevent issues like shared fixtures or strong couplings that make maintenance difficult.

About Q2BSTUDIO: Q2BSTUDIO is a company specialized in custom software development and custom applications, with experience in artificial intelligence, AI for businesses, AI agents, and cybersecurity solutions. We offer AWS and Azure cloud services, business intelligence services, and development of solutions with Power BI for visualization and reporting. Our team designs custom software that integrates artificial intelligence models, automation, and security practices to protect critical data and processes.

Featured services of Q2BSTUDIO: custom software development, cloud architectures on AWS and Azure, consulting in artificial intelligence and AI agents to optimize business operations, cybersecurity projects for infrastructure protection, Power BI integration, and business intelligence services to transform data into actionable decisions.

If you need to improve the testing strategy in your Django project, optimize CI pipelines with pytest xdist and testmon, or develop a custom solution that incorporates artificial intelligence and cybersecurity, Q2BSTUDIO can help you design and implement the right, scalable, and secure solution.

OUR SERVICES

How we can help you

Do you have a project in mind?

Tell us your vision and we'll turn it into a software solution. Whatever the scope, we make your idea real.