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:
We can add a teardown approach:
- setUpClass()
- Per test:
- setUp()
- run test
- tearDown()
- self.addCleanUp functions
- tearDownClass()
- addClassCleanup() functions
TestCase Hierarchy¶
From the docs: 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¶
- setUpClass():tx begin.
- setUpClass():setUpTestData() - data persists for all of test and rolled back at end of tests.
- Per test:
- no need for super()
- _pre_setup():tx begin
- run test
- _post_teardown():tx rollback - data persists just for this test.
- tearDownClass():tx rollback.
setUpTestData()¶
- Called by setUpClass()
- @classmethod
- Default empty - yours so don't need to call super().
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.
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