Hi, my name is Asdrubal Santander, I'm a Backend developer at Mo Tecnologías, and this is a short guide to how we implement testing with Pytest-Django.
Why Pytest?
Pytest it is an alternative framework to write tests in Python besides Unittest, between its best features it has:
- Easy to write
assert
statements just like any other conditionalassert 1 == 1
. No more assertNotNull, assertDictEquals... -
Fixtures
to run code before and after each test, set up state of a test, load fixtures and more! - Better integration with plugins and tools (like pdb, and coverage).
- Improved results, when a test fail it tells you exactly where it fails and with colors!
- Can run tests written with the syntax of Unittest. So it makes easy to change.
Our Project structure:
project_name
├── project
│ ├── apps
│ │ ├── integration_apps
│ │ | ├── app_name
| | | | └── tests
| | | | ├── component_to_be_tested
| | | | | ├── test_function_name.py
| | | | |
| | | | ├── conftest.py
| | | | └── ...
| | | └── ...
| | └── ...
│ ├── project_settings
│ | └── settings
| | ├── development_settings
| | ├── production_settings
| | └── test_settings
| └── manage.py
├── pytest.ini
└── ...
So as you can see, our Django project as an uncommon structure, I will try to explain in a general way:
-
project_name
: config files, requirements folder, README.MD ... -
project
:apps
, fixtures folder,project_settings
andmanage.py
. -
project_settings
:settings
, project urls.py, wsgi.py. -
settings
: settings for our project in this case we are going to be focus ontest_settings
. -
apps
: contains our business logic in separated apps. -
test
: inside this folder we have separatedconftest.py
to an specific app, and is where we are going to put all our tests, separated by folders such like "views", "services", "selectors"...
Installation:
pip install pytest-django
pip install pytest-cov
pip install pytest-pythonpath
-
pytest-django
: A plugin to easily integrate Pytest with Django. -
pytest-cov
: Plugin that helps to create the coverage reports inside Pytest. -
pytest-pythonpath
: Plugin that modifies the env var PYTHONPATH. This is useful when pytest can't find your manage.py
pytest.ini:
[pytest]
addopts = -v -p no:warnings --nomigrations --cov=. --no-cov-on-fail
DJANGO_SETTINGS_MODULE = project.project_settings.settings.test_settings
python_paths = .
With the file pytest.ini
we can set arguments and other configurations, so we don't have to specify each time we run Pytest.
-
addopts
: Special variable to set command line options-
-v
: To tell pytest to be a little bit more verbose -
-p no:warnings
: Disable warnings. -
--nomigrations
: Disable the migrations when run pytest this could make the setup for testing faster. -
--cov=.
: When pytest runs it makes a coverage report. -
--no-cov-on-fail
: Don't show the coverage report if a test fails.
-
DJANGO_SETTINGS_MODULE
: This is where we tell pytest to run with a specific settings.python_paths
: The dot meaning that the current directory will be added to the PYTHONPATH env var.
Running Pytest:
$ pytest
======================================== test session starts ========================================
platform darwin -- Python 3.6.0, pytest-5.2.2, py-1.8.0, pluggy-0.13.0 --
...
cachedir: .pytest_cache
Django settings: project.project_settings.settings.test_settings (from ini file)
rootdir: .../mysite, inifile: pytest.ini
plugins: django-3.7.0, pythonpath-0.7.3, cov-2.8.1
collected 0 items
---------- coverage: platform darwin, python 3.6.0-final-0 -----------
Name Stmts Miss Cover
---------------------------------------------------------------------------------------
...
mo_services/apps/importantapp/test/services/test_function_name.py 0 0 100%
...
--------------------------------------------------------------------------------------------
TOTAL X X XXX%
======================================= no tests ran in 0.09s =======================================
Let's write a example test:
Inside of app_name
we create a python package named tests
, this package will have all the tests for this application divided in sub packages with the name of the component:
# .../apps/integration_apps/app_name/tests/component_to_be_tested/test_function_name.py
from app_name.component_name import some_function
class TestFunctionName:
def test_example():
result = some_function()
expected_result = 'some_result'
assert result == expected_result
Running pytest again:
$ pytest
======================================== test session starts ========================================
platform darwin -- Python 3.6.0, pytest-5.2.2, py-1.8.0, pluggy-0.13.0 --
...
cachedir: .pytest_cache
Django settings: project.project_settings.settings.test_settings (from ini file)
rootdir: .../mysite, inifile: pytest.ini
plugins: django-3.7.0, pythonpath-0.7.3, cov-2.8.1
collected 1 item
apps/integration_apps/app_name/tests/component_to_be_tested/test_function_name.py::TestFunctionName::test_example PASSED [100%]
--------------- coverage: platform darwin, python 3.6.0-final-0 -----------
Name Stmts Miss Cover
--------------------------------------------------------------------------------------------
...
mo_services/apps/importantapp/test/services/test_function_name.py 1 0 100%
...
--------------------------------------------------------------------------------------------
TOTAL X X XXX%
========================================= 1 passed in 0.11s =========================================
So now you have successfully run Pytest in Django!
Some final cool command line options:
-
-x
: This option tells pytest to stop after the first test fail, is great when we are having problems with several tests so in this way we can solve this problems one by one. -
--nf
: Tells pytest to run the "new tests" first. -
--ff
: Tells pytest to run the "fail tests" first. -
--lf
: Tells pytest to run the only the "last fail".
Top comments (1)
Or you can use github.com/wemake-services/wemake-...
It comes with
pytest
already configured. With lots of extra features!wemake-services / wemake-django-template
Bleeding edge django template focused on code quality and security.
wemake-django-template
Bleeding edge
django2.2
template focused on code quality and security.Purpose
This project is used to scaffold a
django
project structure Just likedjango-admin.py startproject
but better.Features
python3.8+
build
,test
, anddeploy
pipeline configured by defaulthttp/2
turned on by defaultInstallation
Firstly, you will need to install dependencies:
Then, create a project itself:
Who are using this template?
If you use our template, please add yourself or your company in the list.
We offer free email support for anyone who is using this If you have any problems or questions,…