pytest之内置fixture函数之request详解(request.params && request.config && request.module && 。。。)
前言
官方文档中request的描述:request是pytest的内置fixture函数;为请求对象提供对请求测试上下文的访问权,并且在fixture函数被间接参数化的情况下具有可选的"param"属性。
对这句话的解读: request 函数是pytest中的内置fixture函数,可以在自定义的fixture函数中调用 request 函数用以获取测试上下文的一些信息。【测试上下文的理解:用例参数化的测试方法(上文)中调用自定义fixture函数(下文)】
FixtureRequest
源代码:【https://docs.pytest.org/en/latest/reference/reference.html#pytest.FixtureRequest】
class FixtureRequest 请求对象提供对请求的测试上下文的访问,并且具有可选的 param 属性,以防设备被间接参数化。 fixturename 正在为其执行此请求的 fixture 名称。 scope 作用域字符串,“function”、“class”、“module”、“session”之一。 fixturenames 此请求中所有活动状态的 fixture 的名称。 node 基础集合节点(取决于当前请求范围)。 config 与此请求关联的 pytest 配置对象。 function 如果请求具有每个函数范围,则测试函数对象。 cls 类(可以是None),其中收集了测试函数。 instance 在其上收集测试函数的实例(可以是None)。 module 收集测试函数的Python模块对象。 fspath 收集此测试的测试模块的文件系统路径。 keywords 基础节点的关键字/标记词典。 session Pytest会话对象。 addfinalizer(finalizer: Callable[], object]) → None[源代码] 添加finalizer/teardown函数,以便在请求的测试上下文中的最后一个测试完成执行后调用。 applymarker(marker) → None[源代码] 对单个测试函数调用应用标记。 如果不希望在所有函数调用上都有关键字/标记,则此方法非常有用。 参数 marker -- A _pytest.mark.MarkDecorator 调用创建的对象 pytest.mark.NAME(...) . raiseerror(msg: Optional[str]) → NoReturn[源代码] 使用给定的消息引发FixtureLookupError。 getfixturevalue(argname: str) → Any[源代码] 动态运行命名的fixture函数。 如果可能,建议通过函数参数声明fixtures。但是,如果您只能在测试设置时决定是否使用另一个fixture,那么您可以使用此函数在fixture或测试函数体中检索它。 引发 pytest.FixtureLookupError -- 如果找不到给定的固定装置。
request.param:用于获取测试的请求参数。【获取测试上下文的信息】
1、可以在fixture函数参数化的时候,通过request.param获取到测试的请求参数。【实现fixture函数的参数化】
①【注意】fixture函数的 params 请求参数数量(请求参数的数据类型为列表/元组,请求参数数量为列表/元组元素个数)决定fixture函数执行的次数。
②【注意】此时fixture函数的装饰器 @pytest.fixture(params=test_data) 参数不能忘记传值。
代码示例:
''' request 是 pytest的内置fixture ''' import pytest # 测试数据 test_data = ["user1", "user2"] @pytest.fixture(params=test_data) def register_users(request): # 获取当前的测试数据 user = request.param print("setup前置函数拿着这个账号去注册:%s"%user) result = "success" return user, result def test_register(register_users): user, result = register_users print("在测试用例里面里面获取到当前测试数据:%s"%user) print(result) assert result == "success"
运行结果:
③【注意】在调用装饰器为 @pytest.fixture(params=test_data) 的fixture函数的测试方法中使用 request.param不能获取到测试的请求参数,即不能获取test_data中的数据。
实例:
import pytest # 测试数据 test_data = ["user1", "user2"] @pytest.fixture(params=test_data) def register_users(request): # 获取当前的测试数据 user = request.param print("setup前置函数:拿着这个账号去注册:%s" % user) result = "success" return user, result def test_register(register_users, request): print(request.param) if __name__ == '__main__': pytest.main(['-vs', __file__])
运行结果:
④【注意】区分request获取自定义参数值:在测试方法中可以调用request内置fixture函数来获得pytest配置对象中指定的自定义参数值。
conftest.py
def pytest_addoption(parser): parser.addoption("--cmdopt", action="store", default=100, type=int, help="将命令行参数'--cmdopt'添加到pytest配置对象中")
test_1.py
def test_request(request): print('\n在测试方法中通过request.config.getoption()方法调用测试参数:', request.config.getoption('cmdopt'))
pytest命令行参数执行
pytest -s --cmdopt=999
运行结果:
2、fixture函数中request.params与测试方法中的用例参数化@pytest.mark.parameter(indirect=Ture)结合使用
①当用例参数化 @pytest.mark.parameter() 的indirect参数为true时,那么argnames参数对应的参数值一定是一个fixture函数【此时的argnames参数不再是一个变量】,而且argvalues参数对应的参数值则是会传到该fixture函数内。
②fixture函数中,通过 request.params 请求对象 获取测试用例参数化时传过来的argvalues参数值,经过此fixture函数内部逻辑对argvalues参数值处理后返回重新将处理后的用例参数化数据返回给测试方法。
③测试方法通过调用此fixture函数获取此fixture函数处理后的新数据。
【注意】此时fixture函数的 @pytest.fixture() 的params参数不需要传值;因为参数值来自测试方法的用例参数化数据。
实例:
运行结果:
request.config:获取pytest配置对象
【具体详细使用与介绍可结合此博客:pytest动态添加命令行参数并获取该参数对应的参数值到程序中(pytest_addoption钩子函数添加指定参数对应的参数值到pytest配置对象中)】
request请求对象的相关成员对象
通过request请求对象来获取测试方法/测试用例中的一些有用的信息。例如某一测试点为XXX的测试用例的参数化数据,某测试方法所处的模块等等。【前提条件:该测试方法主动或自动调用此fixture函数】
实例:
conftest.py
# encoding:utf-8 import pytest @pytest.fixture() def login(request): print("\n=======================request start=================================") print('测试方法的参数化数据:{}'.format(request.param)) print('测试方法所处模块的信息:{}'.format(request.module)) print('测试方法信息:{}'.format(request.function)) print('测试方法所在的类的信息:{}'.format(request.cls)) print('测试方法所在路径信息:{}'.format(request.fspath)) print('测试方法调用的多个fixture函数(比如fixture函数之间的嵌套调用(包括pytest内嵌的fixture函数))信息:{}'.format(request.fixturenames)) print('测试方法调用的单个fixture函数(自己在程序中定义在测试方法中调用的fixture函数)信息:{}'.format(request.fixturename)) print('测试方法级别信息:{}'.format(request.scope)) print("\n=======================request end=================================")
test_a.py
import pytest user = [('张三', '123456'), ('李四', 'abcdefg')] class TestA: @pytest.mark.parametrize(argnames='login', argvalues=user, indirect=True) def test_one_param(self, login): assert True
运行结果: