Reputation: 187
Using Pytest 6.2.5 and SQLAlchemy 1.4 async engine with Postgres backend.
I have two tests that test simple update and read functions. They are SQLAlchemy asyncio
methods. The update test updates a value in the database and the read function asserts that the newly written value is present. Currently these are two separate tests which both pass.
I want to move them into a single test, since they are interdependent.
Placing these two functions into a single test causes the test to fail.
I can see that it is related to the async functionality, but I thought the @pytest.mark.asyncio
decorator and the asyncio.run()
async-specific functionality would account for that.
These two tests pass:
@pytest.mark.asyncio
def test_update():
return asyncio.run(update('appuser', {'name': 'Alice'}, {'org': 'Wonderland'}))
@pytest.mark.asyncio
def test_read():
read = asyncio.run(read('appuser', query={'name': 'Alice'}, mods={'fields': ['org']}))
assert read == [('Wonderland',)]
This fails
@pytest.mark.asyncio
def test_read():
asyncio.run(update('appuser', {'name': 'Alice'}, {'org': 'Wonderland'}))
read = asyncio.run(read('appuser', query={'name': 'Alice'}, mods={'fields': ['org']}))
assert read == [('Wonderland',)]
With this error:
> ???
E RuntimeError: Task <Task pending coro=<PostgresDb.read() running at file.py:262> cb=[_run_until_complete_cb() at /usr/lib/python3.7/asyncio/base_events.py:158]> got Future <Future pending cb=[Protocol._on_waiter_completed()]> attached to a different loop
asyncpg/protocol/protocol.pyx:338: RuntimeError
I tried placing the test_update as a function within the test_read function and calling it from within there like this, but the error is the same:
@pytest.mark.asyncio
def test_read():
def test_update():
asyncio.run(DB.update('appuser', {'name': 'Alice'}, {'org': 'Wonderland'}))
test_update()
read = asyncio.run(DB.read('appuser', query={'name': 'Alice'}, mods={'fields': ['org']}))
assert read == [('Wonderland',)]
How can we run multiple asyncio.run()
functions inside of a single Pytest?
Upvotes: 1
Views: 568
Reputation: 26900
You're mixing regular functions together with async ones.
Using @pytest.mark.asyncio
requires an async function (async def
).
Also, instead of using asyncio.run()
which creates a new loop and can only be used once, try await
ing like so:
@pytest.mark.asyncio
async def test_read():
await update('appuser', {'name': 'Alice'}, {'org': 'Wonderland'})
read = await read('appuser', query={'name': 'Alice'}, mods={'fields': ['org']})
assert read == [('Wonderland',)]
Upvotes: 2