{"id":4269,"library":"starlette-testclient","title":"Starlette TestClient","description":"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.","status":"maintenance","version":"0.4.1","language":"en","source_language":"en","source_url":"https://github.com/Kludex/starlette-testclient","tags":["testing","starlette","fastapi","http","requests","backport"],"install":[{"cmd":"pip install starlette-testclient","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"This library explicitly uses 'requests' as its underlying HTTP client for testing, distinguishing it from modern Starlette's 'httpx'-based TestClient.","package":"requests","optional":false},{"reason":"It is a backport of Starlette's TestClient and is designed to test Starlette (and FastAPI) applications.","package":"starlette","optional":false},{"reason":"Starlette itself is built on 'anyio', and starlette-testclient v0.4.0 added explicit compatibility for 'anyio<3' and 'anyio>=4'.","package":"anyio","optional":false}],"imports":[{"note":"While 'starlette.testclient.TestClient' is valid, it uses 'httpx' and has an asynchronous interface. This library specifically provides a 'requests'-based, synchronous client, which users might mistakenly assume is available via the 'starlette' package itself after framework updates.","wrong":"from starlette.testclient import TestClient","symbol":"TestClient","correct":"from starlette_testclient import TestClient"}],"quickstart":{"code":"from starlette.applications import Starlette\nfrom starlette.responses import PlainTextResponse\nfrom starlette.routing import Route\nfrom starlette_testclient import TestClient\n\nasync def homepage(request):\n    return PlainTextResponse(\"Hello, world!\")\n\nroutes = [\n    Route(\"/\", endpoint=homepage),\n]\n\napp = Starlette(routes=routes)\n\ndef test_homepage_sync():\n    client = TestClient(app)\n    response = client.get(\"/\")\n    assert response.status_code == 200\n    assert response.text == \"Hello, world!\"\n\ntest_homepage_sync()\nprint(\"Quickstart test passed!\")","lang":"python","description":"This example demonstrates how to create a basic Starlette application and then test it using `starlette-testclient`'s synchronous `TestClient`."},"warnings":[{"fix":"Ensure your `anyio` dependency is pinned to `<3` or `>=4`. If using an older `starlette-testclient` version, update to 0.4.0+.","message":"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`.","severity":"gotcha","affected_versions":"<0.4.0 and potentially v0.4.0+ with specific 'anyio' 3.x versions"},{"fix":"Avoid accessing async resources created within the ASGI app's lifecycle directly from `async def` test functions. If async test logic is necessary, use `httpx.AsyncClient` with `ASGITransport` instead, or ensure resources are managed within the same event loop context.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure cookie `max_age` values are integers. Verify that the `TestClient`'s `base_url` aligns with the domain for which cookies are being set, particularly for explicit domain settings.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"As a workaround, you can initialize `TestClient` with `TestClient(app, backend_options={'loop_factory': asyncio.new_event_loop})` or, if using PyCharm, disable `python.debug.asyncio.repl` in `Help | Find Actions | Registry`.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}