3

I'm trying to using pytest-aiohttp to test my aiohttp based REST API. There is an /authenticate endpoint which returns an authentication token and essentially all other endpoints require the token in the Authorization header. I have the following tests which work perfectly:

from pytest import fixture

from agora_backend.server import get_app

NAME, PASSWORD = "clin123", "password123"


@fixture
def client(loop, aiohttp_client):
    return loop.run_until_complete(aiohttp_client(get_app))


async def test_patient_success(client):
    auth_response = await client.post("/authenticate",
        json={"user_name": NAME, "user_pass": PASSWORD})

    auth_token =  await auth_response.text()

    response = await client.get("/clinician/patients",
        headers={"Authorization": f"Bearer {auth_token}"})

    assert response.status == 200


async def test_session_id_success(client):
    auth_response = await client.post("/authenticate",
        json={"user_name": NAME, "user_pass": PASSWORD})

    auth_token =  await auth_response.text()

    response = await client.get("/clinician/session/1",
        headers={"Authorization": f"Bearer {auth_token}"})

    assert response.status == 200

However, this is not very DRY. I would like to use the same authorization token for all of the tests, thus I figured a fixture would be a good choice. So I tried the following code:

from pytest import fixture

from agora_backend.server import get_app

NAME, PASSWORD = "clin123", "password123"


@fixture
def client(loop, aiohttp_client):
    return loop.run_until_complete(aiohttp_client(get_app))


@fixture
async def auth_token(client):
    auth_response = await client.post("/authenticate",
        json={"user_name": NAME, "user_pass": PASSWORD})

    return await auth_response.text()


async def test_patient_success(client, auth_token):
    response = await client.get("/clinician/patients",
        headers={"Authorization": f"Bearer {auth_token}"})

    assert response.status == 200


async def test_session_id_success(client, auth_token):
    response = await client.get("/clinician/session/1",
        headers={"Authorization": f"Bearer {auth_token}"})

    assert response.status == 200

However, this results in the exception RuntimeError: Timeout context manager should be used inside a task. I have tried looking at this seemingly related answer but I'm not sure if it is completely applicable to my situation. And if it is, I don't quite understand how to apply it to my code. Any help would be appreciated!

tedm1106
  • 127
  • 1
  • 10
  • you are better off using `pytest-asyncio` [https://github.com/pytest-dev/pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) for this. You can mark your async tests with the `@pytest.mark.asyncio` descriptor and async fixtures do not need any special treatment. `pytest-asyncio` will handle them on its own. I do not know if `pytest-aiohttp` supports `async` fixtures. The answer that you linked was seemingly using `pytest-asyncio`. – syfluqs Mar 01 '20 at 22:52
  • I have given this a shot. Also tried following [this answer](https://stackoverflow.com/questions/45736201/how-to-use-pytest-aiohttp-fixtures-with-scope-session) but I haven't had much luck initializing my database connection in a session fixture. For now I seem to be stuck with boilerplate. – tedm1106 Mar 02 '20 at 13:21

0 Answers0