为什么将 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
在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