Starlette TestClient AttributeError: _UnixSelectorEventLoop object has no attribute _compute_internal_coro
Upgrade httpx and starlette (pip install --upgrade starlette httpx pytest-asyncio) and use httpx.AsyncClient with ASGITransport for async testing.
Root Cause Analysis
This error occurs when executing test suites with Starlette or FastAPI TestClient under certain Python / OS event loop policies (such as _UnixSelectorEventLoop on Linux/macOS), caused by internal event loop method mismatches between older Starlette and newer anyio/httpx releases.
1. TestClient Architecture Migration to HTTPX
Starlette's TestClient is built on top of httpx. In modern Starlette and HTTPX versions, the transport layer was refactored to use ASGITransport. Mismatched versions of anyio, starlette, and httpx attempt to invoke internal asyncio private coroutine methods that do not exist on Unix selector loops.
2. Event Loop Lifecycle Conflicts in Pytest
Running async test fixtures alongside synchronous TestClient instances within the same thread creates conflicting event loop states.
3. Deprecated Event Loop Policies in Python 3.12+
Python 3.12 changed default asyncio event loop management (e.g. asyncio.get_event_loop() behavior when no loop is running).
4. Mixing Sync TestClient with Async Test Functions
Declaring async def test_endpoint(): client = TestClient(app); response = client.get(...) blocks the active async loop.
Reproduction Code (MCVE)
# **Note de reproductibilité :** Dépendant de l'OS et de la version de Python.
raise AttributeError("'_UnixSelectorEventLoop' object has no attribute '_compute_internal_coro' in starlette.testclient")
Solution 1: Upgrade Test Toolchain to Modern Compatible Releases
Synchronize test dependencies to modern versions supporting Python 3.12.
import sys
print(f'Active Python: {sys.version}')
print('Run in terminal:')
print('pip install --upgrade starlette httpx anyio pytest pytest-asyncio')
Solution 2: Use httpx.AsyncClient with ASGITransport for Async Tests
Use native httpx.AsyncClient with ASGITransport for seamless async testing without synchronous loop conflicts.
print('Modern Async Testing Pattern:')
print('import pytest')
print('from httpx import AsyncClient, ASGITransport')
print('from main import app\n')
print('@pytest.mark.asyncio')
print('async def test_endpoint():')
print(' async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:')
print(' response = await client.get("/")')
print(' assert response.status_code == 200')
A common mistake is using synchronous TestClient inside an async def test_... function without awaiting. Because TestClient runs its own portal event loop, invoking it inside an existing running event loop causes loop deadlocks. Use TestClient in synchronous def test_... functions, and AsyncClient in async def test_... functions. Edge cases occur on Windows with ProactorEventLoop: configure pytest_plugins = ('pytest_asyncio',) in conftest.py. Contrast this error with RuntimeError: Event loop is closed, which occurs when accessing a loop after fixture teardown.