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)

参数:

  • 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()
  • 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")

在这里插入图片描述

  • 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"]

六个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}")

在这里插入图片描述

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))

测试文件:

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}===========")

执行: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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值