如何使用 pytest 将夹具中的对象共享到所有测试?

How to share object from fixture to all tests using pytest?

在具有会话范围和 autouse=True 的夹具中定义对象的最佳方法是什么,以便它可用于所有测试?

@pytest.fixture(scope='session', autouse=True)
def setup_func(request):
    obj = SomeObj()

接下来,我想要一些之前创建的魔法 obj 将出现在每个测试上下文中,而不需要每个测试都定义 setup_func 夹具。

def test_one():
   obj.do_something_fancy()

我的建议是将夹具添加到 conftest.py 并确保 return 您想要从夹具中生成的对象。

如前所述,这使得 "autouse" 有点没用。

在测试的根目录中,将夹具添加到名为 conftest.py:

的文件中
@pytest.fixture(scope='session', autouse=True)
def someobj(request):
    return SomeObj()

根文件下的任何测试文件都可以访问此夹具(例如 test_foo.py):

def test_foo(someobj):
    assert isinstance(someobj, SomeObj)

另一种方法是使用在同一测试中定义或从模块导入的全局变量。

例如 conftest.py:

someobj = None
@pytest.fixture(scope='session', autouse=True)
def prep_someobj(request):
    someobj = SomeObj()

那么在你的测试中:

from . import conftest

def test_foo():
    assert isinstance(conftest.someobj, SomeObj)

在我看来,这比第一种方法可读性差,而且更麻烦。

另一种可能性是将测试包装在 class 中并使用 class 变量只定义一次对象实例。这假设您能够将所有测试包装在一个 class 中,因此这个答案可能会解决一个不太普遍但类似的用例。例如,

class SomeObj():
    """This object definition may exist in another module and be imported."""
    def __init__(self):
        self.x = 5

    def do_something_fancy(self, y):
        return self.x * y


class TestX():
    # Object instance to share across tests
    someobj = SomeObj()

    def test_x(self):
        assert TestX.someobj.x == 5

    def test_fancy(self):
        fancy_factor = 10
        result = TestX.someobj.do_something_fancy(fancy_factor)
        assert result == 50

一个更通用的模式是在您的会议结束时 return locals(),您将能够轻松引用在夹具中创建的任何内容。

conftest.py

@pytest.fixture(scope='session')
def setup_func(request):
    obj1 = SomeObj()
    obj2 = SomeObj()

    return locals()

test_stuff.py

def test_one(setup_func):
   setup_func['obj1'].do_something_fancy()

def test_two(setup_func):
   setup_func['obj2'].do_something_fancy()