13

密切相关: 在 python 中,是否有在 setup/teardown 中使用上下文管理器的好习惯


我有一个上下文管理器,用于在测试中修复时间/时区。我想将它放在 pytest funcarg 中(或夹具,我们使用的是pytest2.2.3,但我可以向后翻译)。我可以这样做:

def pytest_funcarg__fixedTimezone(request):
    # fix timezone to match Qld, no DST to worry about and matches all
    # Eastern states in winter.
    fixedTime = offsetTime.DisplacedRealTime(tz=' Australia/Brisbane')

    def setup():
        fixedTime.__enter__()
        return fixedTime

    def teardown(fixedTime):
        # this seems rather odd?
        fixedTime.__exit__(None, None, None)

...但它有点恶心。在相关的 Q jsbueno中指出:问题是您的代码没有规定在__exit__发生异常时正确调用对象的方法。

他的回答使用了元类方法。但这对于 pytest 来说并不是那么有用,因为 pytest 通常测试只是函数,而不是类。那么解决这个问题的 pytest-y 方法是什么?涉及运行测试钩子的东西?

4

2 回答 2

19

自 2.4 以来,py.test具有yield样式夹具支持。我们可以直接在其中使用with上下文。

@pytest.yield_fixture
def passwd():
    with open("/etc/passwd") as f:
        yield f.readlines()

自 3.0 起,py.test已弃用该@pytest.yield_fixture用法。我们可以@pytest.fixture直接用作上下文管理器。

@pytest.fixture
def passwd():
    with open("/etc/passwd") as f:
        yield f.readlines()
于 2015-04-08T06:49:11.530 回答
1

恐怕目前没有在夹具中使用上下文管理器的优雅方式。但是,如果测试失败,终结器将运行:

import contextlib, pytest

@contextlib.contextmanager
def manager():
    print 'manager enter'
    yield 42
    print 'manager exit'

@pytest.fixture
def fix(request):
    m = manager()
    request.addfinalizer(lambda: m.__exit__(None, None, None))
    return m.__enter__()

def test_foo(fix):
    print fix
    raise Exception('oops')

如果你运行它,pytest -s你会看到__exit__()调用发生了。

于 2013-04-04T12:17:22.333 回答