summaryrefslogtreecommitdiff
path: root/docs/topics/testing
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2020-02-12 15:15:00 -0700
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-03-18 19:59:12 +0100
commitfc0fa72ff4cdbf5861a366e31cb8bbacd44da22d (patch)
treed419ce531586808b0a111664907b859cb6d22862 /docs/topics/testing
parent3f7e4b16bf58f99c71570ba75dc97db8265071be (diff)
Fixed #31224 -- Added support for asynchronous views and middleware.
This implements support for asynchronous views, asynchronous tests, asynchronous middleware, and an asynchronous test client.
Diffstat (limited to 'docs/topics/testing')
-rw-r--r--docs/topics/testing/advanced.txt11
-rw-r--r--docs/topics/testing/tools.txt56
2 files changed, 67 insertions, 0 deletions
diff --git a/docs/topics/testing/advanced.txt b/docs/topics/testing/advanced.txt
index a909c5f3d8..8aca92ea36 100644
--- a/docs/topics/testing/advanced.txt
+++ b/docs/topics/testing/advanced.txt
@@ -67,6 +67,17 @@ The following is a unit test using the request factory::
response = MyView.as_view()(request)
self.assertEqual(response.status_code, 200)
+AsyncRequestFactory
+-------------------
+
+``RequestFactory`` creates WSGI-like requests. If you want to create ASGI-like
+requests, including having a correct ASGI ``scope``, you can instead use
+``django.test.AsyncRequestFactory``.
+
+This class is directly API-compatible with ``RequestFactory``, with the only
+difference being that it returns ``ASGIRequest`` instances rather than
+``WSGIRequest`` instances. All of its methods are still synchronous callables.
+
Testing class-based views
=========================
diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt
index 02433bbf5e..64fee656bb 100644
--- a/docs/topics/testing/tools.txt
+++ b/docs/topics/testing/tools.txt
@@ -1755,6 +1755,62 @@ You can also exclude tests by tag. To run core tests if they are not slow:
test has two tags and you select one of them and exclude the other, the test
won't be run.
+.. _async-tests:
+
+Testing asynchronous code
+=========================
+
+.. versionadded:: 3.1
+
+If you merely want to test the output of your asynchronous views, the standard
+test client will run them inside their own asynchronous loop without any extra
+work needed on your part.
+
+However, if you want to write fully-asynchronous tests for a Django project,
+you will need to take several things into account.
+
+Firstly, your tests must be ``async def`` methods on the test class (in order
+to give them an asynchronous context). Django will automatically detect
+any ``async def`` tests and wrap them so they run in their own event loop.
+
+If you are testing from an asynchronous function, you must also use the
+asynchronous test client. This is available as ``django.test.AsyncClient``,
+or as ``self.async_client`` on any test.
+
+With the exception of the ``follow`` parameter, which is not supported,
+``AsyncClient`` has the same methods and signatures as the synchronous (normal)
+test client, but any method that makes a request must be awaited::
+
+ async def test_my_thing(self):
+ response = await self.async_client.get('/some-url/')
+ self.assertEqual(response.status_code, 200)
+
+The asynchronous client can also call synchronous views; it runs through
+Django's :doc:`asynchronous request path </topics/async>`, which supports both.
+Any view called through the ``AsyncClient`` will get an ``ASGIRequest`` object
+for its ``request`` rather than the ``WSGIRequest`` that the normal client
+creates.
+
+.. warning::
+
+ If you are using test decorators, they must be async-compatible to ensure
+ they work correctly. Django's built-in decorators will behave correctly, but
+ third-party ones may appear to not execute (they will "wrap" the wrong part
+ of the execution flow and not your test).
+
+ If you need to use these decorators, then you should decorate your test
+ methods with :func:`~asgiref.sync.async_to_sync` *inside* of them instead::
+
+ from asgiref.sync import async_to_sync
+ from django.test import TestCase
+
+ class MyTests(TestCase):
+
+ @mock.patch(...)
+ @async_to_sync
+ def test_my_thing(self):
+ ...
+
.. _topics-testing-email:
Email services