Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using @pytest.fixture(scope="module") with @pytest.mark.asyncio

I think the example below is a really common use case:

  1. create a connection to a database once,
  2. pass this connection around to test which insert data
  3. pass the connection to a test which verifies the data.

Changing the scope of @pytest.fixture(scope="module") causes ScopeMismatch: You tried to access the 'function' scoped fixture 'event_loop' with a 'module' scoped request object, involved factories.

Also, the test_insert and test_find coroutine do not need the event_loop argument because the loop is accessible already by passing the connection.

Any ideas how to fix those two issues?

import pytest

@pytest.fixture(scope="function")  # <-- want this to be scope="module"; run once!
@pytest.mark.asyncio
async def connection(event_loop):
    """ Expensive function; want to do in the module scope. Only this function needs `event_loop`!
    """
    conn await = make_connection(event_loop)
    return conn


@pytest.mark.dependency()
@pytest.mark.asyncio
async def test_insert(connection, event_loop):  # <-- does not need event_loop arg
    """ Test insert into database.

        NB does not need event_loop argument; just the connection.
    """
    _id = 0
    success = await connection.insert(_id, "data")
    assert success == True


@pytest.mark.dependency(depends=['test_insert'])
@pytest.mark.asyncio
async def test_find(connection, event_loop):  # <-- does not need event_loop arg
    """ Test database find.

        NB does not need event_loop argument; just the connection.
    """
    _id = 0
    data = await connection.find(_id)
    assert data == "data"
like image 205
Daniel Farrell Avatar asked May 21 '19 10:05

Daniel Farrell


People also ask

What does pytest Mark Asyncio do?

The pytest-asyncio plugin lets you write asynchronous test functions, making it a snap to test your asynchronous code. The plugin also manages the event loop behind the scenes, providing a few options on how to change it if you need to use a custom event loop.

What is scope in pytest fixture?

Fixtures include an optional parameter called scope, which controls how often a fixture gets set up and torn down. The scope parameter to @pytest. fixture() can have the values of function, class, module, or session. The default scope is function.

Can pytest fixtures use other fixtures?

A fixture can use multiple other fixtures. Just like a test method can take multiple fixtures as arguments, a fixture can take multiple other fixtures as arguments and use them to create the fixture value that it returns.

How does fixture work in pytest?

Fixtures define the steps and data that constitute the arrange phase of a test (see Anatomy of a test). In pytest, they are functions you define that serve this purpose. They can also be used to define a test's act phase; this is a powerful technique for designing more complex tests.


1 Answers

The solution is to redefine the event_loop fixture with the module scope. Include that in the test file.

@pytest.fixture(scope="module")
def event_loop():
    loop = asyncio.get_event_loop()
    yield loop
    loop.close()
like image 161
Daniel Farrell Avatar answered Oct 21 '22 17:10

Daniel Farrell