Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add tip about pytest-asyncio fixture and mark.anyio #26

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,52 @@ anyio.run(main)
> [!NOTE]
Consider supporting the creator of [`asgi-lifespan`][asgi-lifespan] [Florimond Manca][florimondmanca] via GitHub Sponsors.

## 6. Use Lifespan State instead of `app.state`
## 6. Use `pytest-asyncio` fixtures to test your FastAPI and ASGI applications

When writing fixtures for your FastAPI applications, you should use [pytest-asyncio](pytest-asyncio) to define fixtures. Besides, if your application has a lifespan, you should use [`asgi-lifespan`](asgi-lifespan) to run the lifespan events.
Comment on lines +212 to +214
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not really my recommendation... 🤔

I recommend using anyio because you already have the dependency.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the asgi-lifespan is mentioned above, no need to mention twice.


```python
from collections.abc import AsyncGenerator

import pytest_asyncio
from httpx import ASGITransport, AsyncClient

# path to your FastAPI application with a lifespan
from path.to.app import app


@pytest_asyncio.fixture
async def client() -> AsyncGenerator[AsyncClient, None]:
async with LifespanManager(app) as manager:
async with AsyncClient(
transport=ASGITransport(app=manager.app),
base_url="http://localhost:8080",
) as client:
yield client


@pytest.mark.asyncio
async def test_app_starts(client: AsyncClient) -> None:
response = await client.get("/")
assert response.status_code == 200
```

As a bonus: since `anyio` is already a dependency, you can mark your test with `pytest.mark.anyio` like this:

```python
# make anyio aware to use asyncio as the backend
@pytest.fixture
def anyio_backend():
return 'asyncio'


@pytest.mark.anyio
async def test_app_starts(client: AsyncClient) -> None:
response = await client.get("/")
assert response.status_code == 200
```

## 7. Use Lifespan State instead of `app.state`

Since not long ago, FastAPI supports the [lifespan state], which defines a standard way to manage objects that need to be created at
startup, and need to be used in the request-response cycle.
Expand Down