首页 > 解决方案 > 在 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()

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

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

- 编辑

我省略了一个额外的约束,即redis_conn夹具用于函数级模拟:

@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级别。

标签: pythonpytestfixturespython-3.9

解决方案


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

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

推荐阅读