• pytest之fixture


    0、文档

    pytest-fixture
    fixture
    pytest-fixture

    1、fixture简介

    @pytest.fixture() 装饰器用于声明函数是一个fixture,该fixture的名字默认为函数名,也可以自己指定名称(通过name参数可指定别名);如果测试用例的参数列表中包含fixture的名字,那么pytest会根据名字检测到该fixture,并在测试函数运行之前执行该fixture。

    • 测试函数可以直接使用fixture名称作为输入参数,在这种情况下,fixture函数返回的fixture实例将被注入。
    • 可以使用yield或者return关键字把fixture函数里的值传递给test函数。
    • 测试函数可以使用多个fixture;
    • fixture本身还可以使用其他的fixture;
    1.1 fixture参数
    @pytest.fixture(scope="function", params=None, autouse=False, ids=None, name=None)
    
    • 1

    参数:

    • scope – 定义被 @pytest.fixture修饰的方法的作用域;有 “function” (默认) “class” , “module” , “package” 或 “session” 。

    session:每次会话只需要运行一次,会话内所有模块、类、方法,都共享这个fixture
    module:每一个.py文件调用一次
    class:每一个类中调用一次
    function:每一个function或者类方法中都会调用

    动态作用域:
    在某些情况下,您可能希望更改​​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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • params – 参数化实现数据驱动(可支持列表、元组、字典列表、字典元组),获取当前参数可使用 request.param

    ①Fixture可选的参数列表,支持列表传入
    ②默认为None,每个param的值。
    ③可通过request.param接受设置的返回值,params中有多少个元素,在测试时,引用次fixture的函数就会调用几次。
    ④可与参数ids一起使用,作为每个参数的标识。

    # -*- coding: utf-8 -*-
    import pytest
    
    
    @pytest.fixture(scope="function", params=["hello", "hi", 123])
    def ddt(request):  # 通过request接收params中的参数
        print("=====setup======")
        yield request.param  # 通过request.param获取当前使用的参数
        print("=====teardown======")
    
    
    class TestDemo:
    
        def test_one(self):
            print("---------hello world--------")
    
        # 因autouse为False,故需显示引用,即测试函数可以直接使用fixture名称作为输入参数
        def test_two(self, ddt):
            print(f"--------{ddt}-------")
    
    
    if __name__ == '__main__':
        pytest.main("-vs")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    • autouse --如果为True,则自动执行fixture,无需在测试函数使用fixture名称作为输入参数。如果为False(默认值),则需要显式引用(测试函数可以直接使用fixture名称作为输入参数)。
    • ids – 当有多个params时,针对每一个param,可以指定id,这个id将变成测试用例名字的一部分。如果没有提供id,id将自动生成。
    • name – 默认是fixture函数的名称,可以通过name参数更改这个fixture的名称。更改后,如果这个fixture被调用,则使用更改后的名称。
    1.2 fixture调用

    1)参数传参:

    • 将fixture函数名当参数传入用例(函数名无引号)
    • 支持多个,支持fixture相互调用时给fixture传参
    • 返回值:fixture执行完毕将返回值赋值给用例参数名,无返回值默认为None

    2)装饰器传参:

    • 支持多个,不支持fixture相互调用时给fixture传参
    • 返回值:不能获取
    • 第一种:传入名字,@pytest.mark.usefixtures(“fixture1”, “fixture2”)
      (字符串格式,带引号的)
    • 第二种:多个可以使用@pytest.mark.usefixture()进行叠加,先执行的放底层,后执行的放上层。

    fixture可相互调用,但要注意:如果级别不同,低级别可以调用高级别,高级别不能调用低级别。

    1.3 fixture的实例化顺序

    影响fixture实例化顺序的三个因素是:

    1. 作用域(scope)
    2. 依赖项
    3. 自动调用(autouse)
    import pytest
    
    
    @pytest.fixture(scope="session")
    def order():
        return []
    
    
    @pytest.fixture
    def func(order):
        order.append("function")
    
    
    @pytest.fixture(scope="class")
    def cls(order):
        order.append("class")
    
    
    @pytest.fixture(scope="module")
    def mod(order):
        order.append("module")
    
    
    @pytest.fixture(scope="package")
    def pack(order):
        order.append("package")
    
    
    @pytest.fixture(scope="session")
    def sess(order):
        order.append("session")
    
    
    class TestClass:
        def test_order(self, func, cls, mod, pack, sess, order):
            assert order == ["session", "package", "module", "class", "function"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    六个fixture函数:
    order:scope为session级别,返回一个空list。
    func: 调用了order,scope为默认的function级别,并实现向order返回的列表中插入”function“的操作。
    cls:调用了order,scope为class级别,并实现向order返回的列表中插入”class“的操作。
    mod:调用了order,scope为module级别,并实现向order返回的列表中插入”module“的操作。
    pack:调用了order,scope为package级别,并实现向order返回的列表中插入”package“的操作。
    sess:调用了order,scope为session级别,并实现向order返回的列表中插入”session“的操作。

    结论:
    1.fixture的scope级别越高,那么它执行的优先级越高。优先级为:session>package>module>class>function
    2.fixture如果存在依赖项,那么它所依赖的fixture函数会先被执行。
    3.同scope级别fixture中,自动使用的fixture会最先执行;若该fixture存在依赖项,则对于调用了fixture的测试函数来说,这些依赖项也可以看做是自动使用的。

    2、局部前置处理

    fixture写在测试文件中:

    import pytest
    
    
    @pytest.fixture()
    def fix_add(request):
        print("fixture拿到的原始参数是:", request.param)
        sum = request.param[0] + request.param[1]
        yield sum
    
    
    @pytest.mark.parametrize("fix_add", [(1, 3), (2, 4)], indirect=True)
    def test_add(fix_add):
        print('-----执行fix_add测试用例------')
        print(f"fixture返回的参数和是:{fix_add}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    3、全局前置处理

    一个工程下可以有多个conftest.py的文件,在工程根目录下设置的conftest文件起到全局作用。在不同子目录下也可以放conftest.py的文件,作用范围只能在该层级以及以下目录生效,另conftest是不能跨模块调用的。在conftest.py定义的fixture不需要进行import,pytest会自动查找使用。

    # -*- coding: utf-8 -*-
    import pytest
    from logic.gen.account.manager import AccountManager
    from util.context.context import Context
    
    
    def pytest_addoption(parser):
        # 自定义命令行参数
        parser.addoption('--passenger', action='store', help='passenger account')
        parser.addoption('--driver', action='store', help='driver account')
    
    
    @pytest.fixture
    def replace_accounts(request):
        # 获取命令行参数的值
        passenger = request.config.getoption('--passenger')
        driver = request.config.getoption('--driver')
        print(f"----------{passenger}---{driver}----------")
        return (
            AccountManager(ctx=Context(), account=passenger),
            AccountManager(ctx=Context(), account=driver))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    测试文件:

    class TestDemo:
    
        # 因autouse为False,故需显示引用,即测试函数可以直接使用fixture名称作为输入参数
        def test_one(self, replace_accounts):
            p, d = replace_accounts[0], replace_accounts[1]
            print(f"==========={type(p)}===========")
            print(f"==========={d}===========")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    执行:python3 -m pytest -vs --passenger HXZPassenger --driver HXZDriver test_666.py
    在这里插入图片描述

    4、实战–用例执行时替换账号(待改进???)

    import importlib
    import pytest
    
    
    @pytest.fixture
    def replace_accounts(request):
        case_name = request.param.get('case_name')
        passenger_phone = request.param.get('passenger_phone')
        driver_phone = request.param.get('driver_phone')
        module_name = "tests.test_{}".format(case_name)
        test_module = importlib.import_module(module_name)  # 通过importlib模块中的import_module函数动态导入指定测试用例模块
        setattr(test_module, "passenger_phone", passenger_phone)  # 用setattr函数来动态修改测试用例中的参数值
        setattr(test_module, "driver_phone", driver_phone)
        return test_module.test_case  # fixture返回修改后的测试用例函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    隐入尘烟影评
    Verilog开源项目——百兆以太网交换机(三)Hash模块设计
    干货分享 | 关于同星硬件接口卡及TSMaster软件常见问题Q&A指南
    银行主动安全纵深防御体系解决方案
    VUE预览PDF文件并利用pdf.js获取鼠标选中的文字和搜索,在iframe中获取选中文字,监听鼠标事件,右键菜单
    node.js+mysql+vue.js+vuex+echarts+elementui全栈后台管理系统
    基于Java+SpringBoot+Vue前后端分离教学资源共享平台系统
    Javascript抓取京东、淘宝商品数据
    测试工程师面试之设计测试用例
    NXP iMX8MM 修改 UART4至 Cortex-A53 核心
  • 原文地址:https://blog.csdn.net/qq_41969287/article/details/130877669