Skip to content

Django Docs

We look at essential items from the docs that will help with out PyTest Suite.

Django's TestCase is built upon UnitTestCase.

Set Up Tests

Based on https://www.youtube.com/watch?v=_8qLxaWMdzE DjangoCon 2021 | Speed up your tests with setUpTestData | Adam Johnson.

The exeample 00_setup\test_testcase_setup_lifecycle.py illustrates the setUp/tearDown life cycle:

Robust use

We can add a teardown approach:

Robust use

  1. setUpClass()
  2. Per test:
    • setUp()
    • run test
    • tearDown()
    • self.addCleanUp functions
  3. tearDownClass()
  4. addClassCleanup() functions

TestCase Hierarchy

From the docs: Hierarchy

Hierarchy

SimpleTestCase

  • Blocks DB access.
  • Adds some assertion methods.
  • Does Django's own per-test setup outsode of setUp(), so you don't need to do super().

TransactionTestCase

  • Allows DB access.
  • Rolls back DBs by wiping and re-adding fixture dataafter each test. This slows down tests. We can see this with 00_setup\test_testcase_setup_lifecycle.py particularly with -vvv verbose option in PyTest.
  • Use to test code that commits transactions which are rolled back.
  • Use if you want to read after a test is committed to DB.

TestCase

  • Rolls back DBs with per-class and per-test transactions so it does not need to wipe all tables as rollback wipes table being used.
  • setUpClass calls setUpTestData().
  • much faster.

LiveServerTestCase

https://docs.djangoproject.com/en/5.0/topics/testing/tools/#liveservertestcase

TLDR; sets up a webserver for testing with playwright, selenium, cypress etc.

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.

The live server listens on localhost and binds to port 0 which uses a free port assigned by the operating system. The server’s URL can be accessed with self.live_server_url during the tests.

Django's TestCase Lifecycle

  1. setUpClass():tx begin.
  2. setUpClass():setUpTestData() - data persists for all of test and rolled back at end of tests.
  3. Per test:
    • no need for super()
    • _pre_setup():tx begin
    • run test
    • _post_teardown():tx rollback - data persists just for this test.
  4. tearDownClass():tx rollback.

setUpTestData()

  • Called by setUpClass()
  • @classmethod
  • Default empty - yours so don't need to call super().

Before

Before

In comparison:

  • Data creation in setUp(): N times
  • Data creation in setUpTestData(): once

setUpTestData() Isolation

This came in with Django 3.2

Databases

RequestFactory v Client

Client

https://docs.djangoproject.com/en/5.0/topics/testing/tools/#the-test-client

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:

Simulate GET and POST requests 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. In short:

Use Django’s test client to establish that the correct template is being rendered and that the template is passed the correct context data.

Use RequestFactory to test view functions directly, bypassing the routing and middleware layers.

Use in-browser frameworks like Selenium to test rendered HTML and the behavior of web pages, namely JavaScript functionality. 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 all of these test types.

from django.test import Client
c = Client()
response = c.post("/login/", {"username": "john", "password": "smith"})
response.status_code
200
response = c.get("/customer/details/")
response.content
b'<!DOCTYPE html...'

By default, the test client will disable any CSRF checks performed by your site.

from django.test import Client
csrf_client = Client(enforce_csrf_checks=True)

Mailbox

https://docs.djangoproject.com/en/5.0/topics/testing/tools/#emptying-the-test-outbox

Emptying the test outbox

If you use any of Django’s custom TestCase classes, the test runner will clear the contents of the test email outbox at the start of each test case.

Isolate apps

https://docs.djangoproject.com/en/5.0/topics/testing/tools/#isolating-apps

One can test individual apps using a decorator or context manager:

from django.db import models
from django.test import SimpleTestCase
from django.test.utils import isolate_apps


class MyModelTests(SimpleTestCase):
    @isolate_apps("app_label")
    def test_model_definition(self):
        class TestModel(models.Model):
            pass

        ...
or

with isolate_apps("app_label"):

    class TestModel(models.Model):
        pass

    ...

Tagging

https://docs.djangoproject.com/en/5.0/topics/testing/tools/#tagging-tests

There are many ways to use this feature and the above link explains this in detail.

from django.test import tag


class SampleTestCase(TestCase):
    @tag("fast")
    def test_fast(self): ...

    @tag("slow")
    def test_slow(self): ...

    @tag("slow", "core")
    def test_slow_but_core(self): ...

or

@tag("slow", "core")
class SampleTestCase(TestCase): ...

or

@tag("foo")
class SampleTestCaseChild(SampleTestCase):
    @tag("bar")
    def test(self): ...

$ python manage.py test --tag=fast