We have multiple resources for writing new unit tests for Django, Wagtial, and Python code:
- CFPB Django and Wagtail unit testing documentation
- The Django testing documentation
- The Wagtail testing documentation
- Real Python's "Testing in Django"
If you have not set up the standalone installation of cfgov-refresh, you can still run the tests if you install Tox in your local installation of Python:
pip install tox
docker-compose exec python bash
Our test suite can either be run in a local virtualenv or in Docker. Please note, the tests run quite slow in Docker.
To run the the full suite of Python tests using Tox, make sure you are in the cfgov-refresh root and then run:
Tox runs different isolated Python environments with different versions of dependencies.
We use it to lint our Python files, check out import sorting, and run unit tests
in both Python 3.6 and Python 3.8.
You can select specific environments using
tox by itself is the same as running:
tox -e lint -e unittest
These default environments are:
lint, which runs our linting tools. We require this environment to pass in CI.
unittest, which runs unit tests against the current production versions of Python, Django, and Wagtail. We require this environment to pass in CI.
In addition, we also have this environment:
unittest-future, which runs unit tests against upcoming versions of Python, Django, and Wagtail. We do not require this environment to pass in CI.
By default this uses a local SQLite database for tests. To override this, you
can set the
TEST_DATABASE_URL environment variable to a database connection
string as supported by dj-database-url.
If you would like to run only a specific test, or the tests for a specific app,
you can provide a dotted path to the test as the final argument to any of the above calls to
tox -e unittest regulations3k.tests.test_regdown
isort can be run using the Tox
tox -e lint
This will run
isort in check-only mode and it will print diffs for imports
that need to be fixed. To automatically fix import sort issues, run:
isort --recursive cfgov/
From the root of
To see Python code coverage information, run
coverage report -m
To see coverage for a limited number of files,
--include argument to
coverage and provide a path to the files you wish to see:
coverage report -m --include=./cfgov/regulations3k/*
Python tests should avoid writing to stdout as part of their normal execution.
To enforce this convention, the tests can be run using a custom Django test
runner that fails if anything is written to stdout. This test runner is at
cfgov.test.StdoutCapturingTestRunner and can be enabled with the
TEST_RUNNER=cfgov.test.StdoutCapturingTestRunner tox -e unittest
This test runner is enabled when tests are run automatically on GitHub Actions, but is not used by default when running tests locally.
If you write Python code that interacts with the GovDelivery subscription API, you can use the functionality provided in
core.govdelivery.MockGovDelivery as a mock interface to avoid the use of
patch in unit tests.
This object behaves similarly to the real
govdelivery.api.GovDelivery class in that it handles all requests and returns a valid (200)
Conveniently for unit testing, all calls are stored in a class-level list that can be retrieved at
MockGovDelivery.calls. This allows for testing of code that interacts with GovDelivery by checking the contents of this list to ensure that the right methods were called.
This pattern is modeled after Django's
django.core.mail.outbox which provides similar functionality for testing sending of emails.
The related classes
ServerErrorMockGovDelivery can similarly be used in unit tests to test for cases where a call to the GovDelivery API raises an exception and returns an HTTP status code of 500, respectively.