Reputation: 97
I'm having a problem with my test setup config using pytest fixture:
@pytest.fixture(autouse=True)
async def run_around_tests(elastic_api, catalog):
es_index_mapping = open('test/resources/es_index_mapping.json')
es_index_mapping_dict = json.load(es_index_mapping)
es_cars = open('test/resources/es_cars.json')
es_cars_dict = json.load(es_cars)
await elastic_api.create_index(index='catalog_test', payload=es_index_mapping_dict)
await catalog.upsert_documents(index='catalog_test', payload=es_cars_dict)
yield
await elastic_api.delete_index(index='catalog_test')
await catalog.close()
Seems like the yield is not executing properly and is not waiting for the tests executions. The deletion of the elasticsearch index happens during the tests execution, causing the tests to fail. Why this deletion is not executing only after all tests finished?
Upvotes: 6
Views: 9566
Reputation: 51
@Dunes provided a great answer (which I discovered after several hours in Async H*ll with misbehaving fixures, tests, etc.) The other thing of note for anyone using pytest-asyncio is that its default event loop is function-scoped, so if you decorate a fixture whose scope is other than "function", you'll get a ScopeMismatch error. If you want to apply the @pytest_asyncio.fixture decorator to a fixture with a scope other than "function" (the default), you need to override the pytest_asyncio event loop scope with another fixture like below. (This does not need autouse'd or injected into other fixtures - pytest-asyncio figures it out, and it applies globally.)
@pytest.fixture(scope="session")
def event_loop(request):
loop = asyncio.new_event_loop()
yield loop
loop.close()
Upvotes: 5
Reputation: 40903
What are you using to drive the async fixtures/tests? pytest does not work out of the box with asyncio. If you're using pytest-asyncio
, then you need to decorate your fixtures with @pytest_asyncio.fixture
rather than the standard @pytest.fixture
.
A good way to test that your fixture is working as expected is to use a simpler fixture and assert it is yielding the right value. i.e.
import asyncio
import pytest
import pytest_asyncio
@pytest.fixture # this decorator isn't quite smart enough to do the right thing
async def bad_fixture():
await asyncio.sleep(0)
yield 'bad_fixture_value'
await asyncio.sleep(0)
@pytest.mark.asyncio
async def test_bad_fixture(bad_fixture):
assert bad_fixture == 'bad_fixture_value' # FAIL
@pytest_asyncio.fixture # dedicated fixture decorator that will do the right thing
async def good_fixture():
await asyncio.sleep(0)
yield 'good_fixture_value'
await asyncio.sleep(0)
@pytest.mark.asyncio
async def test_good_fixture(good_fixture):
assert good_fixture == 'good_fixture_value' # PASS
Upvotes: 12