1

I am using pytest with pytest-asyncio to run async tests. What is strange is that these tests only work if there is exactly one of them. For example:

@pytest.mark.asyncio
async def test_foo():
    client = await get_db_connection()
    user = await client.DO_QUERY
    response = await FunctionUnderTest(
        db=client, ...args
    )
    assert response.id is not None


@pytest.mark.asyncio
async def test_error_foo():
    client = await get_db_connection()

    with pytest.raises(MissingRequiredError):
        await FunctionUnderTest(
            db=client, ...args
        )

If I comment out either of those tests, the remaining one will pass, but running both together gives:

RuntimeError: Task <Task pending name='Task-5' coro=<test_error_foo() running at /tests/test_function_under_test.py:44> cb=[_run_until_complete_cb() at /usr/lib/python3.10/asyncio/base_events.py:184]> got Future <Future pending> attached to a different loop

I would have expected pytest-asyncio to create a single event loop and run all the tests sequentially, but this does not seem to work.

1 Answer 1

1

You'll hopefully get better mileage by using pytest-asyncio-cooperative which is designed around the use of a single event loop for all tests. pytest-asyncio on the other hand uses an event loop per test.

  1. Install:
pip install pytest-asyncio-cooperative
  1. Replace pytest.mark.asyncio with pytest.mark.asyncio_cooperative
@pytest.mark.asyncio_cooperative
async def test_foo():
    client = await get_db_connection()
    user = await client.DO_QUERY
    response = await FunctionUnderTest(
        db=client, ...args
    )
    assert response.id is not None


@pytest.mark.asyncio_cooperative
async def test_error_foo():
    client = await get_db_connection()

    with pytest.raises(MissingRequiredError):
        await FunctionUnderTest(
            db=client, ...args
        )
  1. Run the tests with pytest-asyncio OFF and sequential running of tests ON (ie. --max-asyncio-tasks 1):
pytest -p no:asyncio --max-asyncio-tasks 1 test_function_under_test.py

Admittedly, if you want to keep using pytest-asyncio you could rewrite your tests to use the event loop provided by pytest-asyncio and then explicitly use it in your test. I think you'd have to pass it into your code that is referencing the event loop.

Disclaimer: I am the maintainer of this pytest.mark.asyncio_cooperative

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.