Setup Django for Testing with pytest¶
Test Driven Development is a popular software development practice which helps in creating better software. The practice that I prefer is a little bit relaxed practice that I call Test Assisted Development as sometimes tests are not written before the production code (but let’s leave this discussion for another place and time). Django projects also need to be thoroughly tested. Let’s configure our Django project for testing with pytest before even creating the first Django application.
Overview¶
There are multiple approaches and frameworks for testing Django projects. We are going to use pytest as test framework and pytest_django package.
Tests are stored in elearn/tests directory and follow the package structure of the project being tested.
Test file name should start with test_ in order to be discoverble by pytest. One can decide on different naming convention and modify the test configuration.
Install pytest¶
# ...
pytest
pytest-django
# ....
$ pip install -U requirements.txt
...
Configure Django for Tests¶
Normally all tests should be executed against the same configuration that is being used to run the project in production. However there might be additional settings, e.g. fake Django applications or test management API application etc. that need to be specified only during testing.
To make things simple and straightforward I like defining separate settings modules for three types of environments:
settings.py – the default configuration, used in production
settings_local.py– the local development configuration
settings_test.py – the configurtion used when running tests
Here is what the test configuration looks like:
from .settings import *
At this moment it is just an empty shell that imports all the configuration settings from the default project configuration. We will start adding settings while developing the project.
Configure pytest¶
There are many ways to configure pytest. Here are just some of the options:
Use pytest.ini.
Use pyproject.toml.
Use setup.cfg
All methods use the same configuration settings, just are different in where the configuration settings are stored and slightly different on the syntax.
We are using setup.cfg to configure pytest as it is well supported by Visual Studio Code (VSCode):
1[tool:pytest]
2addopts = --rootdir elearn -s -vv --import-mode importlib
3testpaths =
4 elearn/tests
5DJANGO_SETTINGS_MODULE = elearn.settings_test
Here is the same configuration, but using pyproject.toml:
1[tool.pytest.ini_options]
2addopts = "--rootdir elearn -s --import-mode importlib"
3testpaths = [
4 "elearn/tests",
5]
6DJANGO_SETTINGS_MODULE = "elearn.settings_test"
Setup test directories¶
Create elearn/tests directory
Add empty __init__.py file into it
$ mkdir elearn/tests
$ touch elear/tests/__init__.py
Our First Test Case¶
Let’s create our first test case which confirms our project is up and running, configured correctly and is serving Swagger interface.
We will put our test file in elearn test sub-package. So let’s first create an empty test elearn sub-package:
$ mkdir elearn/tests/elearn
$ touch elearn/tests/elearn/__init__.py
Now we can create a simple test file:
def test_hello_elearn(client):
response = client.get("/docs/")
assert response.status_code == 200
Run all the tests:
$ pytest
========================= test session starts =========================
platform win32 -- Python 3.10.2, pytest-7.4.2, pluggy-0.13.1
django: settings: elearn.settings_test (from ini)
rootdir: D:\Sandbox\repos\django-elearn
configfile: pyproject.toml
testpaths: elearn/tests
plugins: anyio-3.6.2, cov-4.0.0, django-4.5.2
collected 1 item
elearn/tests/elearn/test_hello.py::test_hello_elearn PASSED
========================== 1 passed in 0.53s ==========================
The test case uses a Django test client, provided as pytest fixture by the pytest-djang extension. The test case makes a GET request to the Swagger documentation page (/docs/) and asserts that the response was a success response.