Starlette TestClient
starlette-testclient is a backport of Starlette's TestClient that utilizes the `requests` library instead of `httpx`. Its primary goal is to offer a familiar synchronous testing interface for ASGI applications, easing the migration for users accustomed to `requests`-based testing. The current version is 0.4.1. Releases are infrequent, with the latest significant update in April 2024, reflecting a maintenance cadence focused on compatibility rather than rapid feature development, as its purpose is to bridge the gap for users transitioning from older Starlette testing practices.
Warnings
- gotcha Version 0.4.0 of `starlette-testclient` added explicit support for `anyio<3` and `anyio>=4`. Using `anyio` versions between 3.0 and 3.x (exclusive of <3) may lead to unexpected compatibility issues or errors due to changes in `anyio`'s API, specifically around `start_blocking_portal`.
- gotcha Starlette's `TestClient` (and this backport) executes the ASGI application in a separate background thread, providing a synchronous testing interface for an asynchronous application. This can cause problems when attempting to access asynchronous resources (e.g., database connections, `httpx.AsyncClient` instances) that were initialized within the application's startup events from an `async` test function running in the main thread's event loop.
- gotcha When using `TestClient`, issues with cookies not being set or retrieved correctly have been reported. This can sometimes be traced to `max_age` cookie parameters being floats instead of integers, or inconsistencies between the `base_url` used in the client and the cookie's domain.
- gotcha Debugging tests with `starlette-testclient` in PyCharm (or other IDEs that patch `asyncio` APIs) can lead to `AttributeError` (e.g., `'_UnixSelectorEventLoop' object has no attribute '_compute_internal_coro'`). This occurs because PyCharm's patched `asyncio.new_event_loop()` clashes with `anyio`'s event loop detection.
Install
-
pip install starlette-testclient
Imports
- TestClient
from starlette_testclient import TestClient
Quickstart
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette.routing import Route
from starlette_testclient import TestClient
async def homepage(request):
return PlainTextResponse("Hello, world!")
routes = [
Route("/", endpoint=homepage),
]
app = Starlette(routes=routes)
def test_homepage_sync():
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.text == "Hello, world!"
test_homepage_sync()
print("Quickstart test passed!")