I was getting warnings about pytest-asyncio decorators. Here’s the fix.

Why async tests are tricky Link to heading

Async tests need an event loop to run. pytest-asyncio handles this, but there are gotchas:

  • Each test gets its own event loop by default
  • Fixtures need to match the test’s async-ness
  • Session-scoped async fixtures are fiddly

The old way (deprecated):

@pytest.mark.asyncio
async def test_something():
    result = await some_async_function()
    assert result == expected

The warning says to configure asyncio_mode instead.

The fix Link to heading

In pyproject.toml:

[tool.pytest.ini_options]
asyncio_mode = "auto"

Or in pytest.ini:

[pytest]
asyncio_mode = auto

With auto mode, you don’t need the decorator anymore:

async def test_something():
    result = await some_async_function()
    assert result == expected

pytest-asyncio detects async test functions automatically.

Async fixtures gotchas Link to heading

Async fixtures must be used in async tests:

@pytest.fixture
async def db_connection():
    conn = await create_connection()
    yield conn
    await conn.close()

# This works
async def test_with_db(db_connection):
    await db_connection.execute("SELECT 1")

# This doesn't - can't use async fixture in sync test
def test_sync_with_db(db_connection):  # Error!
    ...

For fixtures that need to be shared across async and sync tests, make them sync and use asyncio.run() internally.

Bulk migration Link to heading

If you have lots of tests with the old decorator, you can remove them in bulk:

rg -l '@pytest.mark.asyncio' tests/ | xargs sed -i '' '/@pytest.mark.asyncio/d'

Note: The sed syntax varies between macOS and Linux.

For general pytest tips, see pytest: last failed and specific tests.

Further reading Link to heading