Django provides a set of tools that come in handy when writing tests.
The Test Client
The test client is a Python class that acts as a dummy Web browser, allowing you to test your views and interact with your Django-powered application programmatically. Some of the things you can do with the test client are:
POSTrequests on a URL and observe the response – everything from low-level HTTP (result headers and status codes) to page content.
- See the chain of redirects (if any) and check the URL and status code at each step.
- Test that a given request is rendered by a given Django template, with a template context that contains certain values.
Note that the test client is not intended to be a replacement for Selenium or other in-browser frameworks. Django’s test client has a different focus.
- Use Django’s test client to establish that the correct template is being rendered and that the template is passed the correct context data.
Django also provides special support for those frameworks; see the section on
LiveServerTestCase for more details. A comprehensive test suite should use a combination of both test types. For a more detailed look at the Django test client with examples, see the Django Project website.
Provided Test Case Classes
Normal Python unit test classes extend a base class of
unittest.TestCase. Django provides a few extensions of this base class:
unittest.TestCase with some basic functionality like:
- Saving and restoring the Python warning machinery state.
- Adding a number of useful assertions including:
- Checking that a callable raises a certain exception.
- Testing form field rendering and error treatment.
- Testing HTML responses for the presence/lack of a given fragment.
- Verifying that a template has/hasn’t been used to generate a given response content.
- Verifying a HTTP redirect is performed by the app.
- Robustly testing two HTML fragments for equality/inequality or containment.
- Robustly testing two XML fragments for equality/inequality.
- Robustly testing two JSON fragments for equality.
- The ability to run tests with modified settings.
- Using the test
- Custom test-time URL maps.
TestCase class (described below) makes use of database transaction facilities to speed up the process of resetting the database to a known state at the beginning of each test. A consequence of this, however, is that some database behaviors cannot be tested within a Django
In those cases, you should use
TestCase are identical except for the manner in which the database is reset to a known state and the ability for test code to test the effects of commit and rollback:
TransactionTestCaseresets the database after the test runs by truncating all tables. A
TransactionTestCasemay call commit and rollback and observe the effects of these calls on the database.
TestCase, on the other hand, does not truncate tables after a test. Instead, it encloses the test code in a database transaction that is rolled back at the end of the test. This guarantees that the rollback at the end of the test restores the database to its initial state.
TransactionTestCase inherits from
This class provides some additional capabilities that can be useful for testing Web sites. Converting a normal
unittest.TestCase to a Django
TestCase is easy: Just change the base class of your test from
django.test.TestCase. All of the standard Python unit test functionality will continue to be available, but it will be augmented with some useful additions, including:
- Automatic loading of fixtures.
- Wraps the tests within two nested
atomicblocks: one for the whole class and one for each test.
- Creates a
- Django-specific assertions for testing for things like redirection and form errors.
TestCase inherits from
LiveServerTestCase does basically the same as
TransactionTestCase with one extra feature: it launches a live Django server in the background on setup, and shuts it down on teardown. This allows the use of automated test clients other than the Django dummy client such as, for example, the Selenium client,
to execute a series of functional tests inside a browser and simulate a real user’s actions.
Test Cases Features
Default Test Client
Every test case in a
*TestCase instance has access to an instance of a Django test client. This client can be accessed as
self.client. This client is recreated for each test, so you don’t have to worry about state (such as cookies) carrying over from one test to another. This means, instead of instantiating a
Client in each test:
… you can just refer to self.client, like so:
A test case for a database-backed Web site isn’t much use if there isn’t any data in the database. To make it easy to put test data into the database, Django’s custom
TransactionTestCase class provides a way of loading fixtures. A fixture is a collection of data that Django knows how to import into a database. For example, if your site has user accounts, you might set up a fixture of fake user accounts in order to populate your database during tests.
The most straightforward way of creating a fixture is to use the
dumpdata command. This assumes you already have some data in your database. (See the
dumpdata documentation for more details).
Once you’ve created a fixture and placed it in a
fixtures directory in one of your
INSTALLED_APPS, you can use it in your unit tests by specifying a
fixtures class attribute on your
Here’s specifically what will happen:
- At the start of each test case, before
setUp()is run, Django will flush the database, returning the database to the state it was in directly after
- Then, all the named fixtures are installed. In this example, Django will install any JSON fixture named
mammals, followed by any fixture named
loaddata documentation for more details on defining and installing fixtures.
This flush/load procedure is repeated for each test in the test case, so you can be certain that the outcome of a test will not be affected by another test, or by the order of test execution. By default, fixtures are only loaded into the
default database. If you are using multiple databases and set
multi_db=True, fixtures will be loaded into all databases.
For testing purposes it’s often useful to change a setting temporarily and revert to the original value after running the testing code. For this use case Django provides a standard Python context manager (see PEP 343) called
settings(), which can be used like this:
This example will override the
LOGIN_URL setting for the code in the
with block and reset its value to the previous state afterwards.
It can prove unwieldy to redefine settings that contain a list of values. In practice, adding or removing values is often sufficient. The
modify_settings() context manager makes it easy:
For each action, you can supply either a list of values or a string. When the value already exists in the list,
prepend have no effect; neither does
remove when the value doesn’t exist.
In case you want to override a setting for a test method, Django provides the
override_settings() decorator (see PEP 318). It’s used like this:
The decorator can also be applied to
Likewise, Django provides the
The decorator can also be applied to test case classes:
When overriding settings, make sure to handle the cases in which your app’s code uses a cache or similar feature that retains state even if the setting is changed. Django provides the
django.test.signals.setting_changed signal that lets you register call-backs to clean up and otherwise reset state when settings are changed.
As Python’s normal
unittest.TestCase class implements assertion methods such as
assertEqual(), Django’s custom
TestCase class provides a number of custom assertion methods that are useful for testing Web applications:
assertRaisesMessage– Asserts that execution of the callable object raised an exception with an
assertFieldOutput– Asserts that a form field behaves correctly with various inputs.
assertFormError– Asserts that a field on a form raises the provided list of errors when rendered on the form.
assertFormsetError– Asserts that the
formsetraises the provided list of errors when rendered.
assertContains– Asserts that a
Responseinstance produced the given
textappears in the content of the response.
assertNotContains– Asserts that a
Responseinstance produced the given
textdoes not appear in the content of the response.
assertTemplateUsed– Asserts that the template with the given name was used in rendering the response. The name is a string such as
assertTemplateNotUsed– Asserts that the template with the given name was not used in rendering the response.
assertRedirects– Asserts that the response returned a
status_coderedirect status, redirected to
GETdata), and that the final page was received with
assertHTMLEqual– Asserts that the strings
html2are equal. The comparison is based on HTML semantics. The comparison takes following things into account:
- Whitespace before and after HTML tags is ignored.
- All types of whitespace are considered equivalent.
- All open tags are closed implicitly, e.g. when a surrounding tag is closed or the HTML document ends.
- Empty tags are equivalent to their self-closing version.
- The ordering of attributes of an HTML element is not significant.
- Attributes without an argument are equal to attributes that equal in name and value (see the examples).
assertHTMLNotEqual– Asserts that the strings
html2are not equal. The comparison is based on HTML semantics. See
assertXMLEqual– Asserts that the strings
xml2are equal. The comparison is based on XML semantics. Similarly to
assertHTMLEqual(), the comparison is made on parsed content, hence only semantic differences are considered, not syntax differences.
assertXMLNotEqual– Asserts that the strings
xml2are not equal. The comparison is based on XML semantics. See
assertInHTML– Asserts that the HTML fragment
needleis contained in the
assertJSONEqual– Asserts that the JSON fragments
assertJSONNotEqual– Asserts that the JSON fragments
expected_dataare not equal.
assertQuerysetEqual– Asserts that a queryset
qsreturns a particular list of values
values. The comparison of the contents of
valuesis performed using the function
transform; by default, this means that the
repr()of each value is compared.
assertNumQueries– Asserts that when
funcis called with
numdatabase queries are executed.
If any of your Django views send email using Django’s email functionality, you probably don’t want to send email each time you run a test using that view. For this reason, Django’s test runner automatically redirects all Django-sent email to a dummy outbox. This lets you test every aspect of sending email – from the number of messages sent to the contents of each message – without actually sending the messages. The test runner accomplishes this by transparently replacing the normal email backend with a testing backend. (Don’t worry – this has no effect on any other email senders outside of Django, such as your machine’s mail server, if you’re running one.)
During test running, each outgoing email is saved in
django.core.mail.outbox. This is a simple list of all
EmailMessage instances that have been sent. The
outbox attribute is a special attribute that is created only when the
locmem email backend is used. It doesn’t normally exist as part of the
django.core.mail module and you can’t import it directly. The code below shows how to access this attribute correctly. Here’s an example test that examines
django.core.mail.outbox for length and contents:
As noted previously, the test outbox is emptied at the start of every test in a Django
*TestCase. To empty the outbox manually, assign the empty list to
Management commands can be tested with the
call_command() function. The output can be redirected into a
unittest library provides the
@skipUnless decorators to allow you to skip tests if you know ahead of time that those tests are going to fail under certain conditions. For example, if your test requires a particular optional library in order to succeed, you could decorate the test case with
@skipIf. Then, the test runner will report that the test wasn’t executed and why, instead of failing the test or omitting the test altogether.
The Test Database
Tests that require a database (namely, model tests) will not use your production database; separate, blank databases are created for the tests. Regardless of whether the tests pass or fail, the test databases are destroyed when all the tests have been executed. You can prevent the test databases from being destroyed by adding the
--keepdb flag to the test command. This will preserve the test database between runs.
If the database does not exist, it will first be created. Any migrations will also be applied in order to keep it up to date. By default, the test databases get their names by prepending
test_ to the value of the
settings for the databases defined in
DATABASES. When using the SQLite database engine, the tests will by default use an in-memory database (i.e., the database will be created in memory, bypassing the filesystem entirely!).
If you want to use a different database name, specify
NAME in the
TEST dictionary for any given database in
DATABASES. On PostgreSQL,
USER will also need read access to the built-in
postgres database. Aside from using a separate database, the test runner will otherwise use all of the same database settings you have in your settings file:
HOST, etc. The test database is created by the user specified by
USER, so you’ll need to make sure that the given user account has sufficient privileges to create a new database on the system.
Using Different Testing Frameworks
unittest is not the only Python testing framework. While Django doesn’t provide explicit support for alternative frameworks, it does provide a way to invoke tests constructed for an alternative framework as if they were normal Django tests.
When you run
./manage.py test, Django looks at the
TEST_RUNNER setting to determine what to do. By default,
TEST_RUNNER points to
django.test.runner.DiscoverRunner. This class defines the default Django testing behavior. This behavior involves:
- Performing global pre-test setup.
- Looking for tests in any file below the current directory whose name matches the pattern
- Creating the test databases.
- Running migrate to install models and initial data into the test databases.
- Running the tests that were found.
- Destroying the test databases.
- Performing global post-test teardown.
If you define your own test runner class and point
TEST_RUNNER at that class, Django will execute your test runner whenever you run
In this way, it’s possible to use any test framework that can be executed from Python code, or to modify the Django test execution process to satisfy whatever testing requirements you may have.
See the Django Project website for more information on using different testing frameworks.
Now that you know how to write tests for your Django projects, we will be moving on to a very important topic once you are ready to turn your project into a real live website – deploying Django to a webserver.