Python装饰器decorators和pytest夹具fixture详解和使用

此前一直认为fixture就叫python中的装饰器,学习后才发现decorators才是装饰器,fixture是pytest框架的夹具,只是通过装饰器去定义和使用。所以要了解fixture就得先了解python装饰器。

一、装饰器(decorators)

1.定义

装饰器(decorators)是 Python 中的一种高级功能,允许动态地修改函数或类的行为。装饰器是一种函数 ,它接受一个函数作为参数,并返回一个新的函数或修改原来的函数。
在这里插入图片描述

2.使用场景

日志记录(函数的调用信息、参数、返回值)、性能分析(函数执行时间)、权限控制(函数访问权限)、缓存(函数结果缓存)

3.装饰器使用方法

我采用一个方法来写清楚它的使用方法以及对参数的接收处理,按步骤查看注释

1)基本语法

#1.声明装饰器函数new_function,用original_function接收原始函数old_function
def new_function(original_function):
	#3.声明一个inner_function方法---接受原始函数的参数并进行处理。
	#*args表示接收任意数量的位置参数--非关键字参数,并打包成一个元组。
	#**kwarg表示接收任意数量的关键字参数--如key=value,并打包成一个字典。
	#两种方式作用为了兼容所有传进来的参数类型
    def inner_function(*args, **kwargs):
        # 4.调用原始函数前添加的新操作
        print("添加的前置操作,对关键字参数进行处理")
        #对关键字参数处理--元组不支持修改
        print("传进来的元组参数:",args)
        print("传进来的关键字参数:",kwargs)
        kwargs["a"]=10
        # 5.将修改后的参数传回
        result = original_function(*args, **kwargs)
        # 6.调用原始函数后添加的新操作
        print("添加的后置操作")
        return result
     #7.返回新函数inner_function
    return inner_function

#8.使用装饰器@new_function,现在调用的函数实际是处理后的新函数
#等同于old_function= new_function(old_function)
@new_function
#2.声明原始函数old_function
def old_function(arg1,arg2,a=None):
    print("原始函数")
    print("修改过后的a:",a)

#9.带参数调用函数
old_function(1, 3, a=4)

执行结果:
在这里插入图片描述
多个装饰器装饰方法时,会依次调用。

2)内置装饰器
除了装饰方法以外,装饰器还可以装饰类。Python 提供了一些内置的装饰器,例如:
@staticmethod: 将方法定义为静态方法,不需要实例化类可直接调用。
@classmethod: 将方法定义为类方法,第一个参数是类本身(通常命名为 cls)。
@property: 将方法转换为属性,使其可以像属性一样访问。

二、fixture夹具

如果理解了装饰器是什么,就不难理解fixture夹具了。在pytest测试框架中,夹具(fixture–英文释义固定器械)是一种用于为测试用例提供预置环境或共享资源的机制。个人理解fixture就是pytest封装好了的一个装饰器函数名称----@pytest.fixture。既然fixture是封装好的,那一定有指定的参数和调用方法。

1.fixture的参数

在这里插入图片描述
如上图封装好的fixture方法可见,fixture有五种传参:

#实例用法
@pytest.fixture(scope='',autouse='',params="",ids="",name="")

1)scope—fixture的作用范围,一共有四种
function(函数级):每一个函数或方法都会调用
class(类级别):每个测试类只运行一次
module(模块级):每一个.py文件调用一次
package(包级):每一个python包只调用一次(暂不支持)
session(会话级):每次会话只需要运行一次,会话内所有方法及类,模块都共享这个方法
执行优先级:session > module > class > function

这个地方先不举例,和2联合起来举例,通过2的示例,将会很清楚scope的执行过程

2)autouse—是否自动执行
默认为False,设置为True后设置的执行范围scope里面包含的所有用例都会执行这个方法。不用再手动在每个要装饰的方法上使用@pytest.mark.usefixture(“fixturename”)。
示例代码:

import logging
import pytest
from allure_commons import fixture

# 会话级别的 fixture - 整个测试运行期间只执行一次
@pytest.fixture(scope="session", autouse=True)
def session_fixture():
    print("\n===== session 范围 fixture 开始 (整个测试会话只执行一次) =====")
    yield
    print("\n===== session 范围 fixture 结束 (所有测试完成后执行) =====")

# 模块级别的 fixture - 每个测试模块只执行一次
@pytest.fixture(scope="module", autouse=True)
def module_fixture():
    print("\n***** module 范围 fixture 开始 (每个.py文件只执行一次) *****")
    yield
    print("\n***** module 范围 fixture 结束 (文件所有测试完成后执行) *****")

# 类级别的 fixture - 每个测试类执行一次
@pytest.fixture(scope="class", autouse=True)
def class_fixture():
    print("\n------ class 范围 fixture 开始 (每个测试类只执行一次) ------")
    yield
    print("\n------ class 范围 fixture 结束 (类中所有测试完成后执行) ------")

# 函数级别的 fixture - 每个测试函数执行一次
@pytest.fixture(scope="function", autouse=True)
def function_fixture():
    print("\n>>>>>> function 范围 fixture 开始 (每个测试方法执行一次) >>>>>>")
    yield
    print("\n<<<<<< function 范围 fixture 结束 (每个测试方法完成后执行) <<<<<<")

def test_outside_class():
    print("执行类外的测试函数")
    assert True

class TestClass:
        def test_case1(self):
            print("执行test_case1")
            assert True
        def test_case2(self):
            print("执行test_case2")
            assert True

执行打印:
在这里插入图片描述
3)params—参数
示例代码:

import pytest

@pytest.fixture(scope="function",params=[1,2,3,4])
#固定写法用request表示参数
def function_fixture(request):
    #固定写法提取参数
    yield request.param

#这里用注释来使用装饰器
@pytest.mark.usefixtures("function_fixture")
def test_param():
    print("test")

运行结果:
在这里插入图片描述

4)ids—给params参数每一个值设置变量名
上述params示例中,可以看到传入了参数1、2、3、4。但是没有参数名称,不太方便去使用。这个ids就是给参数设置变量名。
示例代码:

import pytest

@pytest.fixture(scope="function",params=[1,2,3,4],ids=['p1','p2','p3','p4'])
#固定写法用request表示参数
def function_fixture(request):
    #固定写法提取参数
    yield request.param

#直接在测试函数参数中声明fixture名称来获取参数
def test_param(function_fixture):
    print(f"当前参数值: {function_fixture}")
    print("test")

运行结果:
在这里插入图片描述
5)name–给fixture标记的方法取别名
例如以上的function_fixture我给它起名为fixname
示例代码:

import pytest

@pytest.fixture(scope="function",params=[1,2,3,4],ids=['p1','p2','p3','p4'],name="fixname")
#固定写法用request表示参数
def function_fixture(request):
    #固定写法提取参数
    yield request.param

#直接在测试函数参数中声明fixture名称来获取参数
def test_param(fixname):
    print(f"当前参数值: {fixname}")
    print("test")

运行结果:
在这里插入图片描述

2.fixture配置conftest.py使用

上述代码中是在每个测试用例py中定义的fixture,测试过程中会有很多通用的操作,岂不是每个用例中都要定义一遍,这里就用到了conftest.py来管理。
conftest.py主要作用是用于定义和共享测试配置、Fixture以及其他测试相关的设置、避免重复代码,提高测试代码的可维护性和可重用性,使测试代码本身更专注于测试逻辑—简单的说就是可以跨测试用例共享数据和资源,对测试前后的配置和数据处理等操作
注:和conftest.py同一目录以及子目录的测试均可使用其中装饰器。

示例代码:
test_conf.py

import pytest

def test_conf():
    print("测试conftest.py文件,即使这里没有使用fixture也会调用!!")

conftest.py

import pytest

@pytest.fixture(scope="function", autouse=True)
def function_fixture():
    print("\n>>>>>> function 范围 fixture 开始 (每个测试方法执行一次) >>>>>>")
    yield
    print("\n<<<<<< function 范围 fixture 结束 (每个测试方法完成后执行) <<<<<<")

目录结构:
在这里插入图片描述
运行结果:
在这里插入图片描述
通常配合conftest.py用的还有钩子hook函数。

三、总结

1、decorators装饰器是一种函数 ,它接受一个函数作为参数,并返回一个新的函数或修改原来的函数。----个人理解装饰器就是封装好了一个函数,然后采用"@函数名称()"来注释另一个函数以使用该装饰器,达到某些目的。
2、fixture测试夹具,本质上是一个函数,为测试提供可重用的环境支持。用@pytest.fixture()装饰器将一个函数标记为pytest可识别的fixture夹具。
3、可以用conftest.py来管理共享的装饰器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值