在之前深入理解pytest-repeat插件的工作原理一文中,我们看到pytest_repeat
源码中有这样一段
-
@pytest.fixture
-
def __pytest_repeat_step_number(request):
-
marker = request.node.get_closest_marker("repeat")
-
count = marker and marker.args[0] or request.config.option.count
-
......
看到参数为request
,我们知道fixture装饰的函数入参,只能是其他fixture,所以这里request
一定也是fixture
。那它到底怎么用呢?这篇文章将详细介绍,并通过实战项目加深理解。
request fixture
The request fixture is a special fixture providing information of the requesting test function.
这是pytest
官方文档的介绍,意思就是请求fixture是一个特殊的fixture,提供请求测试函数的信息。
源码直达,感兴趣的朋友可以查看源码FixtureRequest
文档直达
request.node
当前测试用例的节点对象,表示当前执行的测试用例。可以使用该对象获取测试用例的名称、文件路径、测试类等信息。
-
import pytest
-
-
-
@pytest.fixture
-
def my_fixture(request):
-
node = request.node
-
print(f"Current test case: {node.name}")
-
print(f"Test file path: {node.fspath}")
-
print(f"Test class: {node.getparent}")
-
-
-
-
def test_demo(my_fixture):
-
pass
输出结果为:
-
Current test case: test_demo
-
Test file path: /Users/pxl/test_dir/test_demo.py
-
Test class: <bound method Node.getparent of <Function test_demo>>
fixture 使用了 request
参数,并通过 request.node
获取了当前测试用例的相关信息。具体来说,我们打印了当前测试用例的名称、文件路径和测试类名称。
request.config
前运行的配置对象,表示当前 Pytest 的配置信息。可以使用该对象获取命令行参数、配置文件设置等信息。
pytest.ini
-
[pytest]
-
markers =
-
p0: 冒烟
-
p1: 功能
-
@pytest.fixture
-
def my_fixture(request):
-
config = request.config
-
print(f"Command line arguments: {config.option}")
-
print(f"INI file options: {config.getini('markers')}")
该 fixture 使用了 request
参数,并通过 request.config
获取了当前 Pytest 的配置信息。具体来说,我们打印了命令行参数和配置文件中的一个选项。
request.param
当前 fixture 的参数,表示当前 fixture 的实例所需的参数值
-
@pytest.fixture(params=[1, 2, 3])
-
def my_fixture(request):
-
param_value = request.param
-
print(f"Current parameter value: {param_value}")
-
return param_value
该 fixture 使用了 request
参数,并通过 request.param
获取了当前实例所需的参数值。
request.fixturename
返回当前 fixture 的名称。
-
@pytest.fixture
-
def my_fixture(request):
-
fixture_name = request.fixturename
-
print(f"Current fixture name: {fixture_name}")
我们使用 request.fixturename
获取了当前 fixture 的名称,并将其打印出来.
request.fixturenames
返回当前测试函数所使用的所有 fixture 的名称列表
-
@pytest.fixture
-
def my_fixture(request):
-
pass
-
-
def test_example(my_fixture, request):
-
fixture_names = request.fixturenames
-
print(f"Current fixture name: {fixture_names}")
-
我们使用 request.fixturename
s获取了test_example
使用的所有 fixture 的名称
request.cls
当前测试类的类对象。
-
class TestClass:
-
@pytest.fixture
-
def my_fixture(self, request):
-
class_obj = request.cls
-
print(f"Current class object: {class_obj}")
使用 request.cls
获取了当前测试类的类对象,并将其打印出来。
request.addfinalizer(finalizer_func)
在 fixture 完成后执行指定的函数。
-
@pytest.fixture
-
def my_fixture(request):
-
def finalizer_func():
-
print("Finalizer function called")
-
-
request.addfinalizer(finalizer_func)
-
-
print("Fixture setup")
我们使用 request.addfinalizer()
方法注册了一个 finalizer 函数 finalizer_func
。该函数将在 fixture 执行完毕后被调用,并打印一条消息。
request.applymarker(marker)
为当前测试用例或 fixture 应用指定的 marker。
我们使用 request.applymarker()
方法为当前 fixture 添加了一个 pytest.mark.slow
的标记。这个标记可以被 Pytest 识别并用于特定的测试运行策略。
request.config.getoption(name)
获取命令行选项的值。
-
@pytest.fixture
-
def my_fixture(request):
-
my_option = request.config.getoption("--my_option")
-
print(f"Value of --my_option: {my_option}")
我们使用 request.config.getoption()
方法获取了命令行选项 --my_option
的值,并将其打印出来。
request.module
当前测试用例所属的模块对象
-
def my_fixture(request):
-
module_obj = request.module
-
print(f"Current module object: {module_obj}")
我们使用 request.module
获取了当前测试用例所属的模块对象,并将其打印出来
request.param_index
参数化 fixture 的参数索引
-
@pytest.fixture(params=[1, 2, 3])
-
def my_fixture(request):
-
param_value = request.param
-
param_index = request.param_index
-
print(f"Current parameter value: {param_value}")
-
print(f"Current parameter index: {param_index}")
-
return param_value
我们对带有参数的 my_fixture
fixture 进行了参数化。使用 request.param_index
可以获取当前参数在参数列表中的索引,并将其打印出来。
request.keywords
当前测试用例的关键字集合
-
@pytest.fixture
-
def my_fixture(request):
-
keywords = request.keywords
-
print(f"Current test keywords: {keywords}")
我们使用 request.keywords
获取了当前测试用例的关键字集合,并将其打印出来
request.getfixturevalue(fixturename)
获取已注册的 fixture 对象的值
-
import pytest
-
-
@pytest.fixture
-
def my_fixture():
-
return "Hello, Fixture!"
-
-
def test_example(request):
-
fixture_value = request.getfixturevalue("my_fixture")
-
assert fixture_value == "Hello, Fixture!"
-
实战
到这里request fixture
的常用属性和方法应该了解差不多了。更多属性和方法,可以参考官方文档。
接下来我们就利用request
属性实现数据库环境的切换。看实现代码
conftest.py
-
def pytest_addoption(parser):
-
parser.addoption("--test", action="store_true", help="Run tests in test mode")
-
-
-
@pytest.fixture(scope="session")
-
def config_parser(request):
-
class Clazz(object):
-
config = ConfigParser()
-
config.read(config_path)
-
section = 'test' if request.config.getoption("--test") else 'prod'
-
log.info(f"section: {config.sections()}")
-
db_host = config.get(section, 'host')
-
db_port = config.get(section, 'port')
-
db_username = config.get(section, 'username')
-
db_password = config.get(section, 'password')
-
db_database = config.get(section, 'database')
-
api_url = config.get(section, 'url')
-
-
return Clazz
-
-
-
@pytest.fixture(scope="session")
-
def db_connection(config_parser):
-
db_conn = MySQLDB(
-
config_parser.db_host,
-
int(config_parser.db_port),
-
config_parser.db_username,
-
config_parser.db_password,
-
config_parser.db_database
-
)
-
-
yield db_conn
-
-
db_conn.close()
-
config_parser
是一个会话级别的 fixture,它返回一个配置解析器对象。这个配置解析器对象可以读取配置文件,并根据传入的命令行参数--test
来确定读取哪个配置文件的特定部分(测试环境或生产环境)。具体流程如下:a. 首先,在
pytest_addoption
函数中,通过调用parser.addoption()
方法来添加一个命令行选项--test
,它的作用是告诉 pytest 在测试模式下运行。b. 在
config_parser
fixture 中,我们首先创建了一个名为Clazz
的类,它包含了从配置文件中读取的各个配置项的值。c. 根据传入的
--test
参数值,决定使用测试环境还是生产环境的配置。如果--test
参数被指定,则使用配置文件中的test
部分,否则使用prod
部分。d. 通过
config.get()
方法获取具体的配置项的值,例如db_host
、db_port
、db_username
等。e. 最后,将
Clazz
类作为返回值,供其他测试代码使用。 -
db_connection
是一个会话级别的 fixture,它返回一个数据库连接对象。这个对象在测试期间可以被使用,并在测试完成后进行关闭。具体流程如下:a. 在
db_connection
fixture 中,我们创建了一个MySQLDB
对象,将从config_parser
fixture 中获取的数据库连接参数传入。b. 使用
yield
语句将数据库连接对象返回给测试代码。yield
使得这个 fixture 可以在测试期间提供数据库连接,而在测试完成后继续执行下面的代码。c. 在
yield
之后的代码将在测试完成后执行,这里使用db_conn.close()
来关闭数据库连接。
可以看到我们正是使用request.config.getoption
这个方法来 获取命令行选项的值。
这段代码展示了如何使用 pytest 的 fixture 来管理测试环境和资源的初始化和清理。通过使用会话级别的 fixture,可以确保在整个测试会话期间只进行一次配置解析和数据库连接操作,避免重复的开销和不必要的操作。
后续
到这里我们有攻克了一个知识点request
,不仅介绍了它的基本用法,也介绍了笔者在工作中真实使用场景。多加尝试,才能印象深刻。
行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!