starlette/docs/testclient.md

117 lines
4.0 KiB
Markdown
Raw Normal View History

The test client allows you to make requests against your ASGI application,
using the `requests` library.
```python
from starlette.responses import HTMLResponse
2018-08-28 14:18:17 +00:00
from starlette.testclient import TestClient
async def app(scope, receive, send):
assert scope['type'] == 'http'
response = HTMLResponse('<html><body>Hello, world!</body></html>')
await response(scope, receive, send)
def test_app():
client = TestClient(app)
response = client.get('/')
assert response.status_code == 200
```
The test client exposes the same interface as any other `requests` session.
In particular, note that the calls to make a request are just standard
function calls, not awaitables.
You can use any of `requests` standard API, such as authentication, session
cookies handling, or file uploads.
By default the `TestClient` will raise any exceptions that occur in the
application. Occasionally you might want to test the content of 500 error
responses, rather than allowing client to raise the server exception. In this
case you should use `client = TestClient(app, raise_server_exceptions=False)`.
anyio integration (#1157) * First whack at anyio integration * Fix formatting * Remove debug messages * mypy fixes * Update README.md Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> * Fix install_requires typo * move_on_after blocks if deadline is too small * Linter fixes * Improve WSGI structured concurrency * Tests use anyio * Checkin progress on testclient * Prep for anyio 3 * Remove debug backend option * Use anyio 3.0.0rc1 * Remove old style executor from GraphQLApp * Fix extra import * Don't cancel task scope early * Wait for wsgi sender to finish before exiting * Use memory object streams in websocket tests * Test on asyncio, asyncio+uvloop, and trio * Formatting fixes * run_until_first_complete doesn't need a return * Fix middleware app call * Simplify middleware exceptions * Use anyio for websocket test * Set STARLETTE_TESTCLIENT_ASYNC_BACKEND in tests * Pass async backend to portal * Formatting fixes * Bump anyio * Cleanup portals and add TestClient.async_backend * Use anyio.run_async_from_thread to send from worker thread * Use websocket_connect as context manager * Document changes in TestClient * Formatting fix * Fix websocket raises coverage * Update to anyio 3.0.0rc3 and replace aiofiles * Apply suggestions from code review Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> * Bump to require anyio 3.0.0 final * Remove mention of aiofiles in README.md * Pin jinja2 to releases before 3 due to DeprecationWarnings * Add task_group as application attribute * Remove run_until_first_complete * Undo jinja pin * Refactor anyio.sleep into an event * Use one less task in test_websocket_concurrency_pattern * Apply review suggestions * Rename argument * fix start_task_soon type * fix BaseHTTPMiddleware when used without Starlette * Testclient receive() is a non-trapping function if the response is already complete This allows for a zero deadline when waiting for a disconnect message * Use variable annotation for async_backend * Update docs regarding dependency on anyio * Use CancelScope instead of move_on_after in request.is_disconnected * Cancel task group after returning middleware response Add test for https://github.com/encode/starlette/issues/1022 * Add link to anyio backend options in testclient docs * Add types-dataclasses * Re-implement starlette.concurrency.run_until_first_complete and add a test * Fix type on handler callable * Apply review comments to clarify run_until_first_complete scope Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> Co-authored-by: Thomas Grainger <tagrain@gmail.com>
2021-06-18 14:48:43 +00:00
### Selecting the Async backend
`TestClient` takes arguments `backend` (a string) and `backend_options` (a dictionary).
These options are passed to `anyio.start_blocking_portal()`. See the [anyio documentation](https://anyio.readthedocs.io/en/stable/basics.html#backend-options)
for more information about the accepted backend options.
By default, `asyncio` is used with default options.
anyio integration (#1157) * First whack at anyio integration * Fix formatting * Remove debug messages * mypy fixes * Update README.md Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> * Fix install_requires typo * move_on_after blocks if deadline is too small * Linter fixes * Improve WSGI structured concurrency * Tests use anyio * Checkin progress on testclient * Prep for anyio 3 * Remove debug backend option * Use anyio 3.0.0rc1 * Remove old style executor from GraphQLApp * Fix extra import * Don't cancel task scope early * Wait for wsgi sender to finish before exiting * Use memory object streams in websocket tests * Test on asyncio, asyncio+uvloop, and trio * Formatting fixes * run_until_first_complete doesn't need a return * Fix middleware app call * Simplify middleware exceptions * Use anyio for websocket test * Set STARLETTE_TESTCLIENT_ASYNC_BACKEND in tests * Pass async backend to portal * Formatting fixes * Bump anyio * Cleanup portals and add TestClient.async_backend * Use anyio.run_async_from_thread to send from worker thread * Use websocket_connect as context manager * Document changes in TestClient * Formatting fix * Fix websocket raises coverage * Update to anyio 3.0.0rc3 and replace aiofiles * Apply suggestions from code review Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> * Bump to require anyio 3.0.0 final * Remove mention of aiofiles in README.md * Pin jinja2 to releases before 3 due to DeprecationWarnings * Add task_group as application attribute * Remove run_until_first_complete * Undo jinja pin * Refactor anyio.sleep into an event * Use one less task in test_websocket_concurrency_pattern * Apply review suggestions * Rename argument * fix start_task_soon type * fix BaseHTTPMiddleware when used without Starlette * Testclient receive() is a non-trapping function if the response is already complete This allows for a zero deadline when waiting for a disconnect message * Use variable annotation for async_backend * Update docs regarding dependency on anyio * Use CancelScope instead of move_on_after in request.is_disconnected * Cancel task group after returning middleware response Add test for https://github.com/encode/starlette/issues/1022 * Add link to anyio backend options in testclient docs * Add types-dataclasses * Re-implement starlette.concurrency.run_until_first_complete and add a test * Fix type on handler callable * Apply review comments to clarify run_until_first_complete scope Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> Co-authored-by: Thomas Grainger <tagrain@gmail.com>
2021-06-18 14:48:43 +00:00
To run `Trio`, pass `backend="trio"`. For example:
anyio integration (#1157) * First whack at anyio integration * Fix formatting * Remove debug messages * mypy fixes * Update README.md Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> * Fix install_requires typo * move_on_after blocks if deadline is too small * Linter fixes * Improve WSGI structured concurrency * Tests use anyio * Checkin progress on testclient * Prep for anyio 3 * Remove debug backend option * Use anyio 3.0.0rc1 * Remove old style executor from GraphQLApp * Fix extra import * Don't cancel task scope early * Wait for wsgi sender to finish before exiting * Use memory object streams in websocket tests * Test on asyncio, asyncio+uvloop, and trio * Formatting fixes * run_until_first_complete doesn't need a return * Fix middleware app call * Simplify middleware exceptions * Use anyio for websocket test * Set STARLETTE_TESTCLIENT_ASYNC_BACKEND in tests * Pass async backend to portal * Formatting fixes * Bump anyio * Cleanup portals and add TestClient.async_backend * Use anyio.run_async_from_thread to send from worker thread * Use websocket_connect as context manager * Document changes in TestClient * Formatting fix * Fix websocket raises coverage * Update to anyio 3.0.0rc3 and replace aiofiles * Apply suggestions from code review Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> * Bump to require anyio 3.0.0 final * Remove mention of aiofiles in README.md * Pin jinja2 to releases before 3 due to DeprecationWarnings * Add task_group as application attribute * Remove run_until_first_complete * Undo jinja pin * Refactor anyio.sleep into an event * Use one less task in test_websocket_concurrency_pattern * Apply review suggestions * Rename argument * fix start_task_soon type * fix BaseHTTPMiddleware when used without Starlette * Testclient receive() is a non-trapping function if the response is already complete This allows for a zero deadline when waiting for a disconnect message * Use variable annotation for async_backend * Update docs regarding dependency on anyio * Use CancelScope instead of move_on_after in request.is_disconnected * Cancel task group after returning middleware response Add test for https://github.com/encode/starlette/issues/1022 * Add link to anyio backend options in testclient docs * Add types-dataclasses * Re-implement starlette.concurrency.run_until_first_complete and add a test * Fix type on handler callable * Apply review comments to clarify run_until_first_complete scope Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> Co-authored-by: Thomas Grainger <tagrain@gmail.com>
2021-06-18 14:48:43 +00:00
```python
def test_app()
with TestClient(app, backend="trio") as client:
...
```
To run `asyncio` with `uvloop`, pass `backend_options={"use_uvloop": True}`. For example:
```python
def test_app()
with TestClient(app, backend_options={"use_uvloop": True}) as client:
...
anyio integration (#1157) * First whack at anyio integration * Fix formatting * Remove debug messages * mypy fixes * Update README.md Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> * Fix install_requires typo * move_on_after blocks if deadline is too small * Linter fixes * Improve WSGI structured concurrency * Tests use anyio * Checkin progress on testclient * Prep for anyio 3 * Remove debug backend option * Use anyio 3.0.0rc1 * Remove old style executor from GraphQLApp * Fix extra import * Don't cancel task scope early * Wait for wsgi sender to finish before exiting * Use memory object streams in websocket tests * Test on asyncio, asyncio+uvloop, and trio * Formatting fixes * run_until_first_complete doesn't need a return * Fix middleware app call * Simplify middleware exceptions * Use anyio for websocket test * Set STARLETTE_TESTCLIENT_ASYNC_BACKEND in tests * Pass async backend to portal * Formatting fixes * Bump anyio * Cleanup portals and add TestClient.async_backend * Use anyio.run_async_from_thread to send from worker thread * Use websocket_connect as context manager * Document changes in TestClient * Formatting fix * Fix websocket raises coverage * Update to anyio 3.0.0rc3 and replace aiofiles * Apply suggestions from code review Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> * Bump to require anyio 3.0.0 final * Remove mention of aiofiles in README.md * Pin jinja2 to releases before 3 due to DeprecationWarnings * Add task_group as application attribute * Remove run_until_first_complete * Undo jinja pin * Refactor anyio.sleep into an event * Use one less task in test_websocket_concurrency_pattern * Apply review suggestions * Rename argument * fix start_task_soon type * fix BaseHTTPMiddleware when used without Starlette * Testclient receive() is a non-trapping function if the response is already complete This allows for a zero deadline when waiting for a disconnect message * Use variable annotation for async_backend * Update docs regarding dependency on anyio * Use CancelScope instead of move_on_after in request.is_disconnected * Cancel task group after returning middleware response Add test for https://github.com/encode/starlette/issues/1022 * Add link to anyio backend options in testclient docs * Add types-dataclasses * Re-implement starlette.concurrency.run_until_first_complete and add a test * Fix type on handler callable * Apply review comments to clarify run_until_first_complete scope Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> Co-authored-by: Thomas Grainger <tagrain@gmail.com>
2021-06-18 14:48:43 +00:00
```
### Testing WebSocket sessions
You can also test websocket sessions with the test client.
The `requests` library will be used to build the initial handshake, meaning you
can use the same authentication options and other headers between both http and
websocket testing.
```python
from starlette.testclient import TestClient
from starlette.websockets import WebSocket
async def app(scope, receive, send):
assert scope['type'] == 'websocket'
websocket = WebSocket(scope, receive=receive, send=send)
await websocket.accept()
await websocket.send_text('Hello, world!')
await websocket.close()
def test_app():
client = TestClient(app)
with client.websocket_connect('/') as websocket:
data = websocket.receive_text()
assert data == 'Hello, world!'
```
The operations on session are standard function calls, not awaitables.
It's important to use the session within a context-managed `with` block. This
ensure that the background thread on which the ASGI application is properly
terminated, and that any exceptions that occur within the application are
always raised by the test client.
#### Establishing a test session
2018-08-28 14:18:17 +00:00
* `.websocket_connect(url, subprotocols=None, **options)` - Takes the same set of arguments as `requests.get()`.
May raise `starlette.websockets.WebSocketDisconnect` if the application does not accept the websocket connection.
anyio integration (#1157) * First whack at anyio integration * Fix formatting * Remove debug messages * mypy fixes * Update README.md Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> * Fix install_requires typo * move_on_after blocks if deadline is too small * Linter fixes * Improve WSGI structured concurrency * Tests use anyio * Checkin progress on testclient * Prep for anyio 3 * Remove debug backend option * Use anyio 3.0.0rc1 * Remove old style executor from GraphQLApp * Fix extra import * Don't cancel task scope early * Wait for wsgi sender to finish before exiting * Use memory object streams in websocket tests * Test on asyncio, asyncio+uvloop, and trio * Formatting fixes * run_until_first_complete doesn't need a return * Fix middleware app call * Simplify middleware exceptions * Use anyio for websocket test * Set STARLETTE_TESTCLIENT_ASYNC_BACKEND in tests * Pass async backend to portal * Formatting fixes * Bump anyio * Cleanup portals and add TestClient.async_backend * Use anyio.run_async_from_thread to send from worker thread * Use websocket_connect as context manager * Document changes in TestClient * Formatting fix * Fix websocket raises coverage * Update to anyio 3.0.0rc3 and replace aiofiles * Apply suggestions from code review Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> * Bump to require anyio 3.0.0 final * Remove mention of aiofiles in README.md * Pin jinja2 to releases before 3 due to DeprecationWarnings * Add task_group as application attribute * Remove run_until_first_complete * Undo jinja pin * Refactor anyio.sleep into an event * Use one less task in test_websocket_concurrency_pattern * Apply review suggestions * Rename argument * fix start_task_soon type * fix BaseHTTPMiddleware when used without Starlette * Testclient receive() is a non-trapping function if the response is already complete This allows for a zero deadline when waiting for a disconnect message * Use variable annotation for async_backend * Update docs regarding dependency on anyio * Use CancelScope instead of move_on_after in request.is_disconnected * Cancel task group after returning middleware response Add test for https://github.com/encode/starlette/issues/1022 * Add link to anyio backend options in testclient docs * Add types-dataclasses * Re-implement starlette.concurrency.run_until_first_complete and add a test * Fix type on handler callable * Apply review comments to clarify run_until_first_complete scope Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com> Co-authored-by: Alex Grönholm <alex.gronholm@nextday.fi> Co-authored-by: Thomas Grainger <tagrain@gmail.com>
2021-06-18 14:48:43 +00:00
`websocket_connect()` must be used as a context manager (in a `with` block).
2018-08-28 14:18:17 +00:00
#### Sending data
* `.send_text(data)` - Send the given text to the application.
* `.send_bytes(data)` - Send the given bytes to the application.
* `.send_json(data, mode="text")` - Send the given data to the application. Use `mode="binary"` to send JSON over binary data frames.
2018-08-28 14:18:17 +00:00
#### Receiving data
* `.receive_text()` - Wait for incoming text sent by the application and return it.
* `.receive_bytes()` - Wait for incoming bytestring sent by the application and return it.
* `.receive_json(mode="text")` - Wait for incoming json data sent by the application and return it. Use `mode="binary"` to send JSON over binary data frames.
May raise `starlette.websockets.WebSocketDisconnect`.
#### Closing the connection
* `.close(code=1000)` - Perform a client-side close of the websocket connection.