pytest fixture-作用域:class、module、package或session共享fixture
需要网络访问的fixture
依赖于连接,通常需要花费大量的时间来创建。扩展前面的例子,我们可以给@pytest
添加一个scope="module"
参数。fixture
调用smtp_connection fixture
函数,该函数负责创建到先前存在的SMTP服务器的连接,每个测试模块只调用一次(默认情况下是每个测试函数调用一次)。因此,一个测试模块中的多个测试函数将接收相同的smtp_connection fixture
实例,从而节省时间。作用域的可能值有:函数、类、模块、包或会话。
下一个示例将fixture
函数放入一个单独的conftest.py
文件中,以便目录中多个测试模块的测试可以访问fixture
函数:
# content of conftest.py
import pytest
import smtplib
@pytest.fixture(scope="module")
def smtp_connection():
return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
# content of test_module.py
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
assert 0 # for demo purposes
def test_noop(smtp_connection):
response, msg = smtp_connection.noop()
assert response == 250
assert 0 # for demo purposes
在这里, test_ehlo
需要 smtp_connection fixture
值。 pytest 将发现并调用 @pytest.fixture
标记的 smtp_connection fixture
函数。 运行测试如下所示:
$ pytest test_module.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items
test_module.py FF [100%]
================================= FAILURES =================================
________________________________ test_ehlo _________________________________
smtp_connection = <smtplib.SMTP object at 0xdeadbeef0001>
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
> assert 0 # for demo purposes
E assert 0
test_module.py:7: AssertionError
________________________________ test_noop _________________________________
smtp_connection = <smtplib.SMTP object at 0xdeadbeef0001>
def test_noop(smtp_connection):
response, msg = smtp_connection.noop()
assert response == 250
> assert 0 # for demo purposes
E assert 0
test_module.py:13: AssertionError
========================= short test summary info ==========================
FAILED test_module.py::test_ehlo - assert 0
FAILED test_module.py::test_noop - assert 0
============================ 2 failed in 0.12s =============================
您会看到两个 assert 0
失败,更重要的是,您还可以看到完全相同的 smtp_connection
对象被传递到两个测试函数中,因为 pytest 在回溯中显示了传入的参数值。 因此,使用 smtp_connection
的两个测试函数的运行速度与单个测试函数一样快,因为它们重用了相同的实例。
如果你想要一个会话作用域的smtp_connection
实例,你可以简单地声明它:
@pytest.fixture(scope="session")
def smtp_connection():
# the returned fixture value will be shared for
# all tests requesting it
...
Fixture作用域
fixture
在第一次被测试请求时被创建,并根据它们的作用域被销毁:
-
function
:默认作用域,fixture
在测试结束时销毁。 -
class
:在class中的最后一个测试拆除期间,fixture
被销毁。 -
module
:在module的最后一次测试拆卸时,fixture
被破坏。 -
package
:在package中的最后一次测试拆卸时,fixture
被破坏。 -
session
:fixture在测试session结束时被销毁。
Pytest一次只缓存一个fixture
的一个实例,这意味着当使用参数化的fixture
时,Pytest可以在给定范围内多次调用一个fixture
。
动态作用域
在某些情况下,您可能希望更改fixture
的作用域而不更改代码。为此,将一个可调用对象传递给scope
。该可调用对象必须返回一个具有有效作用域的字符串,并且只会执行一次——在fixture
定义期间。它将使用两个关键字参数调用——fixture_name
作为字符串,config
使用配置对象。
这在处理需要时间安装的fixture
时特别有用,比如生成一个docker
容器。您可以使用命令行参数来控制派生容器在不同环境下的作用域。参见下面的示例。
def determine_scope(fixture_name, config):
if config.getoption("--keep-containers", None):
return "session"
return "function"
@pytest.fixture(scope=determine_scope)
def docker_container():
yield spawn_container()
更多建议: