23.16 What changed in the test framework
What changed in django.test from 5.0 to this commit: the test clients’ query_params, coroutine methods and redirects, the backend ClientMixin chooses, a TransactionTestCase’s first set-up, the guard on connections in threads, the assertions, and the runner’s --durations, forkserver and serialized databases.
The framework kept the shape that The test framework describes; what changed is in its parts.
The test clients
Since 5.1 the methods of RequestFactory, AsyncRequestFactory, Client and AsyncClient take query_params, a mapping that becomes the query string of any method’s request: RequestFactory url-encodes it as the environ’s "QUERY_STRING", AsyncRequestFactory as the scope’s "query_string". On RequestFactory and RequestFactory, whose data is the query too, giving both is a ValueError. Given to the constructor of RequestFactory or Client, the mapping reaches no request that generic builds, since it sets "QUERY_STRING" over the default (Building a request: RequestFactory).
ClientMixin declares ClientMixin, ClientMixin, ClientMixin and ClientMixin (5.0), coroutine twins of the session property and of the login and logout methods, on both clients (ClientMixin; Sessions and logins in the test client: ClientMixin and force_login). AsyncClient’s methods have taken follow=True since 5.0, but ClientMixin, which it shares with Client, reads the request’s WSGI keys for a relative Location and for a 307 or 308, and a scope has none: in a run, AsyncClient raised KeyError for both, which Client followed (ClientMixin; The test client: Client and ClientHandler).
ClientMixin, given no backend, takes the first entry of AUTHENTICATION_BACKENDS whose class overrides BaseBackend or BaseBackend, by which later requests find the user; before 6.2 a backend that answers only permissions could be chosen.
The test cases
Since 5.2 TransactionTestCase, for a class that is not a TestCase, runs the first test’s _pre_setup, a class method, and sets SimpleTestCase so that SimpleTestCase does not run it again. A class’s TransactionTestCase and the rows of TransactionTestCase are thus in the database during its own setUpClass, once that has called the parent’s (Emptying the tables after each test: TransactionTestCase).
Since 5.2 django/ sets __unittest = True, the mark by which unittest leaves a module’s frames out of a reported traceback, so a failing assertion of Django’s is reported at the test’s own line and, the release notes add, --pdb enters the test method (__unittest; One test, in order: SimpleTestCase).
The guard that refuses a SimpleTestCase the databases it does not name replaces connection methods in the thread that sets the class up. Since 5.1, “to enforce test isolation” in the release notes’ words, it also replaces BaseDatabaseWrapper for the class, refusing a new connection to such an alias in any thread: in a run, a query in a thread the test started raised DatabaseOperationForbidden for “threaded connections” (SimpleTestCase; Which databases a test uses: databases).
The undocumented module django.test.selenium went in 6.2; importing it is a ModuleNotFoundError.
The assertions
| assertion | what changed | release | where now |
|---|---|---|---|
Simple, Simple |
what changed the message ends with the body, as bytes | release 5.1 | where now Simple django/ |
| the same, on a streaming response | what changed can be called again: the body read is put back as Streaming |
release 6.1 | where now Simple django/ |
Simple |
what changed the message ends with the haystack; ": " follows a msg_prefix |
release 5.1 | where now Simple django/ |
Simple |
what changed new: assertInHTML with count=0 |
release 5.1 | where now Simple django/ |
Simple |
what changed ": " follows a msg_prefix |
release 5.1 | where now Simple django/ |
Simple, Simple |
what changed take a form or a formset, not a response and a name; errors=None, once no errors, is now [None] |
release 5.0 | where now Simple django/ |
| assertFormsetError | what changed removed for assert |
release 5.1 | where now Simple django/ |
| assertQuerysetEqual | what changed removed for Transaction |
release 5.1 | where now Transaction django/ |
The runner and the test databases
--durations (5.0) is added by DiscoverRunner and passed to unittest, which reports the slowest tests (DiscoverRunner; The runner: the test command and DiscoverRunner). The release notes gave it for Python 3.12 and later, now the oldest Python Django supports (pyproject.toml).
Since 6.0 a parallel run works under the forkserver start method, which _init_worker treats as spawn: each worker starts without the parent’s state, sets Django and the test environment up again and takes the parent’s database settings (_init_worker; Running in parallel: ParallelTestSuite). Since 6.1 setup_test_environment gives each alias of a project’s MAILERS the local-memory backend, and sets EMAIL_BACKEND only without it (setup_test_environment; What changed in mail and tasks).
The extra_tests argument of DiscoverRunner and DiscoverRunner went in 5.0, but both still take **kwargs and use none, so the argument is accepted and ignored.
setup_databases serializes the rows a class with serialized_rollback gets back after every test database is made, which its comment says is for mirrors and routing, and, called by the runner, only for the aliases such classes use (setup_databases; Test databases: BaseDatabaseCreation). The serialize argument of BaseDatabaseCreation, which when true serializes one database as it is made, warns with RemovedInDjango2028Warning whenever it is not None (6.0); the release notes name BaseDatabaseCreation in its place, the warning’s message a DatabaseCreation.serialize_test_db that no class defines (BaseDatabaseCreation; What still warns: the deprecations and the releases that end them). The SERIALIZE test setting went in 5.0, deprecated in 4.0 as inferable from the tests’ serialized_rollback; nothing reads the key now.