在 PyTest 中的测试模块结束时断开夹具的连接

Disconnect fixture's connection at the end of test module in PyTest

我有一个测试模块运行 PyTest。

固定装置建立与 Redis 客户端的连接并在每次测试结束时刷新所有:

@pytest.fixture
def redis_conn():
    conn = redis.Redis(decode_responses=True, **config.redis_test_credentials)
    yield conn
    conn.flushall()

除此之外,我需要在模块中的所有测试完成后调用它:

conn.connection.disconnect()

我考虑过的一些事情以及它们为什么不起作用:

  • 我不能在这里使用 pytest.fixture(scope='module') 因为只有在这个模块的测试全部完成后 conn.flushall() 才会 运行

  • 我也不知道如何使用 pytest_unconfigure(),因为我看不到从那里访问 conn 对象的方法。

如何确保在模块中的所有测试完成后执行 conn.connection.disconnect(),同时在每次测试后保持 conn.flushall()

-- 编辑

我省略了一个附加约束,即 redis_conn fixture 用于函数级模拟:

@pytest.fixture
def mock_redis_conn(mocker, redis_conn):
    """ Mock Redis connection """
    mocker.patch("mymodule.api.redis_conn", new=redis_conn)

这个模拟的 mymodule.api.redis_conn 应该在每次测试 运行 之后有效地调用 flushall(),这阻止了我将这个模拟的范围限定到 module 级别。

您可以实现依赖于其他固定装置的固定装置。

from unittest.mock import MagicMock

import pytest

class RedisConn:
    """just stub for example"""
    def flush(self):
        raise NotImplementedError()

connection = RedisConn()

@pytest.fixture(scope="module")
def conn():
    conn = MagicMock()  # here you open connection to testing Redis instance
    print("open connection")
    yield conn
    print("close connection")

@pytest.fixture(scope="function")
def flush(conn, mocker):
    mocker.patch(f"{__name__}.connection", new=conn)
    print("do nothing")
    yield
    print(f"flush {connection}")
    connection.flush()

def test_main_1(flush):
    assert isinstance(connection, MagicMock)
    print("test 1 body")

def test_main_2(flush):
    assert isinstance(connection, MagicMock)
    print("test 2 body")

def test_main_3():
    assert not isinstance(connection, MagicMock)
    assert isinstance(connection, RedisConn)



if __name__ == "__main__":
    pytest.main([__file__, "-s"])

打印

open connection
do nothing
test 1 body
.
flush <MagicMock id='139710977083536'>
do nothing
test 2 body
.
flush <MagicMock id='139710977083536'>
.
close connection