使用@pytest.fixture(scope="module")和@pytest.mark.asyncio

10 人关注

我认为下面的例子是一个非常常见的用例。

  • create a connection to a database once ,
  • pass this connection around to test which insert data
  • pass the connection to a test which verifies the data.
  • 改变 @pytest.fixture(scope="module") 的范围会导致 ScopeMismatch: You tried to access the 'function' scoped fixture 'event_loop' with a 'module' scoped request object, involved factories

    另外, test_insert test_find 的coroutine不需要event_loop参数,因为循环已经可以通过传递连接访问。

    有什么办法可以解决这两个问题吗?

    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"
        
    2 个评论
    不要使用他们提供的默认的 event-loop 夹具,你必须制作你自己的夹具并将其传递给你的夹具。他们的默认夹具,如文档中所述,是针对函数的,所以你不能像你想要的那样在 module 夹具中使用它
    谢谢,这让我走上了正确的道路。
    python
    pytest
    python-asyncio
    pytest-asyncio
    Daniel Farrell
    Daniel Farrell
    发布于 2019-05-21
    2 个回答
    Daniel Farrell
    Daniel Farrell
    发布于 2020-08-20
    已采纳
    0 人赞同

    解决办法是用模块范围重新定义event_loop夹具。在测试文件中包括这一点。

    @pytest.fixture(scope="module")
    def event_loop():
        loop = asyncio.get_event_loop()
        yield loop
        loop.close()
        
    另外,最好是有 scope=session 。你将能够在其他会话范围的固定程序中使用 event_loop 。没有理由为每个模块设置单独的循环。
    谢谢你指出这一点,在某些情况下会很有用。但是这里的 get_event_loop 是返回线程的默认循环,所以在模块范围内(或函数范围内)没有问题。
    shrey khare
    shrey khare
    发布于 2020-08-20
    0 人赞同

    类似的ScopeMismatch问题在github上被提出,用于pytest-asyncio ( link ). The solution (below) works for me:

    @pytest.yield_fixture(scope='class')