Async fixtures with pytest
Coroutine functions are not natively supported by PyTest, so you need to install additional framework for it
- pytest-aiohttp
- pytest-asyncio
- pytest-trio
- pytest-tornasync
If you use pytest-aiohttp, your problem solves in this way
import asyncio
import pytest
from app import db
url = 'postgresql://postgres:postgres@localhost:5432'
@pytest.fixture(scope='session')
def loop():
return asyncio.get_event_loop()
@pytest.fixture(scope='session', autouse=True)
async def prepare_db(loop):
async with db.with_bind(f'{url}/postgres') as engine:
await engine.status(db.text('CREATE DATABASE test_db'))
await db.set_bind(f'{url}/test_db')
await db.gino.create_all()
yield
await db.bind.close()
async with db.with_bind(f'{url}/postgres') as engine:
await engine.status(db.text('DROP DATABASE test_db'))
Main idea is using synchronous loop-fixture
which will be used by async fixtures
You only need to mark your tests as async
@pytest.mark.asyncio
async def test_app(create_x, auth):
api_client, x_id = create_x
resp = await api_client.get(f'my_res/{x_id}', headers=auth)
assert resp.status == web.HTTPOk.status_code
This tells pytest to run the test inside an event loop rather than calling it directly.
The fixtures can be marked as normal
@pytest.fixture
async def create_x(api_client):
x_id = await add_x(api_client)
return api_client, x_id