为什么将 pytest 工厂作为固定装置用于工厂功能?

Why would a pytest factory as fixture be used over a factory function?

py.test docs中它描述了将工厂方法声明为fixture,像这样:

@pytest.fixture
def make_foo():
    def __make_foo(name):
        foo = Foo()
        foo.name = name
        return foo
    return __make_foo

与仅定义 make_foo 函数并使用它相比,这样做的 benefits/tradeoffs 是什么?不明白为什么是夹具

一个示例可能是会话级固定装置,例如:

@pytest.fixture(scope="session")
def make_foo():
    def __make_foo(name):
        foo = Foo()
        foo.name = name
        return foo
    return __make_foo

这样,Pytest 将确保在测试期间只有一个工厂实例存在。尤其是这个例子也许并没有从中得到太多,但是如果外部函数做了很多处理,比如从文件中读取或者初始化数据结构,那么这总体上可以节省你很多时间。

其实最重要的优势是可以使用其他fixture,让pytest的依赖注入为你工作。 另一个优点是允许您将参数传递给工厂,这在普通夹具中必须是静态的。

看这个例子:

@pytest.fixture
def mocked_server():
    with mock.patch('something'):
        yield MyServer()


@pytest.fixture
def connected_client(mocked_server):
    client = Client()
    client.connect_to(mocked_server, local_port=123)  # local_port must be static
    return client

您现在可以编写获得 connected_client 的测试,但不能更改端口。 如果您需要对多个客户进行测试怎么办?你也不行。

如果你现在写:

@pytest.fixture
def connect_client(mocked_server):
    def __connect(local_port):
        client = Client()
        client.connect_to(mocked_server, local_port)
        return client
    return __connect

您可以编写接收 connect_client 工厂的测试,并调用它以在任何端口获取初始化的客户端,以及您想要多少次!

请参阅下面的代码,这可以回答您的问题..

import pytest
@pytest.fixture
def make_foo():
    def __make_foo(name):
        print(name)
    return __make_foo

def test_a(make_foo):
    make_foo('abc')

def test_b(make_foo):
    make_foo('def')

输出如下所示::

tmp3.py::test_a abc
PASSED
tmp3.py::test_b def
PASSED

基本上你可以在factory fixture中传递参数,可以根据你的要求使用。

如果您有很多简单的工厂,那么您可以使用装饰器简化它们的创建:

def factory_fixture(factory):
    @pytest.fixture(scope='session')
    def maker():
        return factory

    maker.__name__ = factory.__name__
    return maker


@factory_fixture
def make_stuff(foo, bar):
    return 'foo' + str(foo + bar)

这相当于

@pytest.fixture(score='session')
def make_stuff():
    def make(foo, bar):
        return 'foo' + str(foo + bar)
    return