Houman
Houman

Reputation: 66410

Multiple async unit tests fail, but running them one by one will pass

I have two unit tests, if I run them one by one, they pass. If I run them at class level, one pass and the other one fails at response = await ac.post( with the error message: RuntimeError: Event loop is closed

@pytest.mark.asyncio
async def test_successful_register_saves_expiry_to_seven_days(self):
    async with AsyncClient(app=app, base_url="http://127.0.0.1") as ac:
        response = await ac.post(
            "/register/",
            headers={},
            json={
                "device_id": "u1",
                "device_type": DeviceType.IPHONE.value,
            },
        )
        query = device.select(whereclause=device.c.id == "u1")
        d = await db.fetch_one(query)
        assert d.expires_at == datetime.utcnow().replace(
            second=0, microsecond=0
        ) + timedelta(days=7)

@pytest.mark.asyncio
async def test_successful_register_saves_device_type(self):
    async with AsyncClient(app=app, base_url="http://127.0.0.1") as ac:
        response = await ac.post(
            "/register/",
            headers={},
            json={
                "device_id": "u1",
                "device_type": DeviceType.ANDROID.value,
            },
        )
        query = device.select(whereclause=device.c.id == "u1")
        d = await db.fetch_one(query)
        assert d.type == DeviceType.ANDROID.value

I have been trying for hours, what am I missing please?

Upvotes: 7

Views: 3533

Answers (1)

Houman
Houman

Reputation: 66410

UPDATE (>= 0.19.0)

Latest 0.19.0 of pytest-asyncio has become strict. You need now to change every @pytest.fixture in the conftest.py with @pytest_asyncio.fixture.

These things keep changing too often.


UPDATE (< 0.19.0)

It is true that @pytest.yield_fixture is deprecated. The proper way until version 0.19.0 is

@pytest.fixture(scope="session")
def event_loop(request):
    loop = asyncio.get_event_loop()
    yield loop
    loop.close()

Original Answer:

I have found the solution.

Create a file named conftest.py under tests

And insert the following:

@pytest.yield_fixture(scope="session")
def event_loop(request):
    """Create an instance of the default event loop for each test case."""
    loop = asyncio.get_event_loop_policy().new_event_loop()
    yield loop
    loop.close()

This will correctly end the loop after each test and allow multiple ones to be run.

Upvotes: 19

Related Questions