Open-Source Wikis

/

Django

/

Systems

/

Test framework

django/django

Test framework

django/test/ is Django's testing toolkit: TestCase subclasses, the Client HTTP simulator, the DiscoverRunner test orchestrator, and a pile of helpers that make Django apps testable without spinning up a server.

Purpose

Make it possible to test views, models, forms, templates, and management commands inside a single process, with fast database isolation and accurate URL routing. The framework's own test suite is the most demanding consumer: 1,986 test files, ~348k lines, run on every PR across multiple databases and Python versions.

Directory layout

django/test/
├── __init__.py
├── client.py          # Client, AsyncClient, RequestFactory (~58 KB)
├── html.py            # parse_html, assertHTMLEqual helpers
├── runner.py          # DiscoverRunner, ParallelTestSuite (~37 KB)
├── selenium.py        # SeleniumTestCase
├── signals.py         # template_rendered, setting_changed
├── testcases.py       # SimpleTestCase, TransactionTestCase, TestCase, LiveServerTestCase (~58 KB)
└── utils.py           # override_settings, modify_settings, captured_stdout, …

Key abstractions

Type File Role
SimpleTestCase testcases.py No DB; fastest. Inherits unittest.TestCase plus Django assertions
TransactionTestCase testcases.py Each test wraps in a transaction-truncate cycle
TestCase testcases.py Each test wraps in a transaction that rolls back; the default
LiveServerTestCase testcases.py Spins up a thread-served WSGI server
StaticLiveServerTestCase testcases.py LiveServerTestCase with staticfiles serving
Client client.py Fake HTTP client; bypasses the network
AsyncClient client.py Async variant
RequestFactory client.py Build HttpRequest instances directly
DiscoverRunner runner.py The default test runner
ParallelTestSuite runner.py Worker process orchestration
override_settings, modify_settings utils.py Decorators / context managers for setting overrides
CaptureQueriesContext utils.py Capture every SQL statement in a block
isolate_apps utils.py Register temporary apps for a test
tag testcases.py @tag decorator for selective runs

Testing levels

graph TD
    Sim["SimpleTestCase<br/>no DB"]
    Tx["TestCase<br/>(transaction rollback)"]
    Trunc["TransactionTestCase<br/>(truncate)"]
    Live["LiveServerTestCase<br/>(thread server)"]
    Sel["SeleniumTestCase<br/>(LiveServer + browser)"]
    Slow["slowest"]
    Fast["fastest"]

    Fast --> Sim
    Sim --> Tx
    Tx --> Trunc
    Trunc --> Live
    Live --> Sel
    Sel --> Slow

Use the lightest class that supports your test:

  • SimpleTestCase for tests that don't touch the database.
  • TestCase for the typical case: transactions are rolled back per test, isolation is cheap.
  • TransactionTestCase when you need raw SQL, on-commit hooks, or savepoint semantics that the rolled-back outer transaction would interfere with.
  • LiveServerTestCase for end-to-end tests that need a real socket.

How TestCase isolates state

TestCase.setUpClass() opens a transaction. TestCase.setUp() opens a savepoint. After each test, the savepoint rolls back. After the class finishes, the outer transaction rolls back. The database is never actually mutated.

This is fast (~microseconds per rollback) but means tests can't observe each other's changes. If you need to test transaction commit behaviour, use TransactionTestCase instead.

TestCase.setUpTestData(cls) is a class-method hook for objects that should be created once and shared across all test methods in a class. Each test gets a fresh transaction, but setUpTestData runs in the outer transaction. Use it instead of fixtures for performance.

The test client

django.test.client.Client is a fake HTTP client. It bypasses the network entirely and dispatches requests directly to the WSGI handler:

def test_login(self):
    response = self.client.post("/login/", {"username": "alice", "password": "x"})
    self.assertRedirects(response, "/")

The client maintains state across calls (cookies, session, login). Client.login() sets up an authenticated session without going through the auth views. Client.force_login() bypasses authentication entirely (useful for testing protected views).

AsyncClient mirrors the API for async views. RequestFactory (and AsyncRequestFactory) build HttpRequest instances directly without dispatching — useful for unit-testing view callables.

The client follows redirects by default (configurable). It exposes the rendered template list (response.templates) for assertTemplateUsed. It captures the test database state, the rendered response, and the resolver match.

Assertions

SimpleTestCase adds Django-aware assertions on top of unittest.TestCase:

  • assertContains(response, text, count=None, status_code=200)
  • assertNotContains(response, text)
  • assertRedirects(response, expected_url, status_code=302, target_status_code=200)
  • assertTemplateUsed(response, template_name) / assertTemplateNotUsed
  • assertFormError(response, form, field, errors) / assertFormSetError
  • assertHTMLEqual(html1, html2) / assertHTMLNotEqual
  • assertJSONEqual(json1, json2) / assertJSONNotEqual
  • assertXMLEqual(xml1, xml2)
  • assertNumQueries(num)
  • assertQuerySetEqual(qs, values, transform=None, ordered=True)
  • assertInHTML(needle, haystack) — substring match in normalised HTML.
  • assertRaisesMessage(exception_class, message)assertRaises with substring match on str(exception).

The runner

DiscoverRunner (django/test/runner.py) does:

  1. Setup — collect tests via unittest.defaultTestLoader.discover from each test app.
  2. Database setupsetup_databases() creates a test DB per configured backend (named test_<dbname>).
  3. Run — execute the test suite; in parallel mode, fork workers and dispatch sub-suites.
  4. Teardown — drop test DBs (unless --keepdb).

Flags worth knowing:

  • --keepdb — don't drop the test database between runs. Hugely faster during development.
  • --parallel <N> — fork N worker processes.
  • --reverse — run tests in reverse order. Useful for catching test-ordering bugs.
  • --shuffle [seed] — randomise test order.
  • --debug-sql — print SQL on test failure.
  • --debug-mode — set DEBUG = True during the run.
  • -v 2 — verbose output.
  • --tag a --tag b --exclude-tag c — filter by @tag decorations.
  • --pdb — drop into pdb on error.
  • -k pattern — substring match on test name.

The custom TEST_RUNNER setting lets projects swap in alternatives (pytest-django uses this).

Override settings

override_settings is the workhorse for changing settings inside a test:

@override_settings(DEBUG=True)
def test_with_debug(self):
    ...

with override_settings(DEBUG=True):
    ...

@override_settings(DEBUG=True)
class MyTests(TestCase):
    ...

It sends setting_changed so subsystems can rebuild caches. modify_settings is the variant for list-valued settings (MIDDLEWARE, INSTALLED_APPS):

@modify_settings(INSTALLED_APPS={"append": "myapp"})
def test_with_app(self):
    ...

Capturing SQL

from django.test.utils import CaptureQueriesContext
from django.db import connection

with CaptureQueriesContext(connection) as ctx:
    ...
print(len(ctx.captured_queries))

assertNumQueries(n) is the same thing wrapped in an assertion.

Parallelisation

DiscoverRunner forks worker processes (one per --parallel <N>) using multiprocessing. Each worker:

  • Gets a copy of the test database (with a unique suffix).
  • Runs a partition of the test suite.
  • Reports results to the parent.

Tests opt out by setting _overridden_settings["allow_database_queries"] = False (rare) or by being subclasses that don't support parallelisation (TransactionTestCase with serialized_rollback, LiveServerTestCase).

Selenium

django/test/selenium.py provides SeleniumTestCase for browser automation. It's a LiveServerTestCase plus a selenium.webdriver instance. The framework uses it for admin tests that need real browser behaviour.

Integration points

  • Settingsoverride_settings interacts with setting_changed.
  • ORMsetup_databases() and teardown_databases() use the schema editor.
  • Signalstemplate_rendered is fired during template renders so assertTemplateUsed can collect them.
  • URL resolverClient.get() uses the same resolver as production.
  • Async supportAsyncClient and IsolatedAsyncioTestCase both work.
  • Management commandsruntests.py and manage.py test both delegate here.

Entry points for modification

  • Custom test runner: subclass DiscoverRunner, set TEST_RUNNER. Override run_tests, setup_databases, teardown_databases.
  • New assertion: add a method to SimpleTestCase if it's broadly useful, otherwise extend in a project base class.
  • New TestCase mix-in: subclass SimpleTestCase or TestCase and add the helpers.

Key source files

File Purpose
django/test/testcases.py All *TestCase classes (~58 KB)
django/test/client.py Client, AsyncClient, RequestFactory (~58 KB)
django/test/runner.py DiscoverRunner, parallel suite (~37 KB)
django/test/utils.py override_settings, CaptureQueriesContext, helpers
django/test/selenium.py SeleniumTestCase
django/test/signals.py template_rendered, setting_changed
django/test/html.py parse_html and assertHTMLEqual machinery

Where to read tests

  • tests/test_runner/ — the runner itself.
  • tests/test_client/, tests/test_client_regress/Client behaviour.
  • tests/test_utils/ — utilities like override_settings.
  • tests/transaction_hooks/on_commit and transaction interaction.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Test framework – Django wiki | Factory