Testing Async FastAPI with pytest-asyncio
To test async code, your tests must also be async. `pytest-asyncio` lets you write `async def test_...` functions to `await` operations like database checks after an API call.
WHY IT EXISTS: Standard pytest functions are synchronous. When testing a FastAPI application that interacts with other asynchronous systems, like an async database driver or an external async API, the test itself needs to await those interactions to verify outcomes. A synchronous test function cannot await a coroutine, making end-to-end validation impossible.
THE MENTAL MODEL: Think of @pytest.mark.asyncio as a bridge. It tells the pytest runner, "This isn't a regular function; it's an async coroutine. Please run it inside an asyncio event loop." This allows your test function to speak the same async/await language as your application code and its dependencies. Without it, your async def test_... is just a coroutine object that never gets executed.
HOW IT WORKS: FastAPI's TestClient is built on HTTPX and can make requests synchronously. However, to perform async operations within the test function itself, you must mark the test with @pytest.mark.asyncio (from the pytest-asyncio library) and define it with async def. This provides the necessary event loop to await other functions, like a query to your database to confirm a write operation succeeded.
WHEN TO USE IT: Use async tests whenever your validation logic requires interacting with an async resource. The classic case is testing a "create" endpoint: first, you send a POST request to your app; second, you await a call to your async database to confirm the new record exists and is correct.
WHEN NOT TO USE IT: If your test only needs to check the HTTP response (status code, JSON body) and doesn't interact with any other async systems, a standard synchronous test is simpler and sufficient. The regular TestClient handles the async nature of the endpoint internally, so you don't need to make the test itself async for simple cases.
ONE CANONICAL EXAMPLE: To test an endpoint that writes to a database, you first define the test with @pytest.mark.asyncio and async def. Inside the test, you use an AsyncClient to await a POST request to your app. After asserting the HTTP response is correct, you then await a separate async database query function to fetch the record you just created. Finally, you assert that the data in the database matches what you sent. This confirms the end-to-end async flow worked correctly.
Read the original → fastapi.tiangolo.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.