如何在自动化测试中应用装饰器、多线程优化自动化架构?

news2024/11/22 17:16:30

1、装饰器概念

        装饰器是Python中用于修改函数或类的语法结构的工具。它以函数作为输入参数,并返回一个函数作为一个输出函数,在不改变原有函数的代码情况下,给函数增加功能或改变函数行为。

        装饰器的使用方式是在函数定义的上方使用 @decorator_name 的形式将装饰器应用到函数上,这样定义的函数在被调用时会先执行装饰器函数,再执行原始函数。常见的装饰器有类装饰器、函数装饰器、属性装饰器等。

        装饰器本身需要接受一个被装饰的对象作为参数,该参数通常为函数、方法、类等对象。

        装饰器需要返回一个对象,该对象可以是 经过处理的原参数对象、一个包装且类似原参数的对象

1.1 最简单的装饰器

def my_decorator(func):
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper


@my_decorator
def say_hello():
    print("Hello!")


say_hello()

 如代码所示:

1、当我们调用被装饰器修饰的函数的时候,首先会把 say_hello 的函数传入 my_decorator
的 func 参数中,然后再去执行内部的 wrapper 函数(在这个函数内部就会操作很多东西,比如增删改等操作),最后返回 wrapper 函数。

2、实际上我们调用的 say helo 函数没有被执行,那这里为什么执行了呢?是因为 wrapper函数里面又调用了一次它,如果不调用,那么 say hello 函数就是一个装饰,但是通常情况下都会调用一次来达到我们的一些特殊目的。

1.2 用于修改对象和函数的装饰器 

def wrap(obj):
    obj.name = 'python'
    return obj

@wrap
class Bar(object):
    def __init__(self, name):
        pass

print(Bar.name)

@wrap
def foo():
    pass

print(foo.name)

 可以看到实际的使用过程中,warp装饰器已经成功的给Bar对象添加了name属性。除了给类对象添加属性之外,它还可以给函数对象添加属性。

1.3 用于模拟对象的装饰器-函数装饰器【重点中的重点】

用于模拟对象的装饰器--函数装饰器
上面例子中的装饰器,是直接修改了传入对象,而装饰器最常用的方式却是模拟一个传入对象。即返回一个和原对象相似的对象(即调用接口完全一样的另一个对象),并且该模拟对象是包装了原对象在内的。具体代码如下:

def outer(func):
    def inner():
        print("Hello inner")
        func()
    return inner
@outer
def foo():
    print("Hello foo")

print(foo.__name__)
foo()

上面是一个函数装饰器,即用来修饰函数的装饰器因为它返回了一个模拟func对象的inner对象。而这里inner对象是一个函数,所以这个装饰器只能装饰函数。(因为inner对象只能模拟func这样的函数对象,不能模拟class对象)
可以看到首先打印的是 foo._name_代码,注意内容是inner而不是foo(说明其本质上是inner函数);其次打印的时候,先打印inner函数中的内容,后打印foo函数中的内容。

Python 中被装饰后的函数,函数名等函数属性会发生改变(相当于另一个函数了)所以,Python 的functools 包中提供了一个叫 wraps 的装饰器来解决该问题。它能使其保留原有函数的结构。 

1.4 用于模拟对象的装饰器

def outer(obj):
    def inner(self):
        print('hello inner')
        obj(self)
    return inner

class Zoo(object):
    def _init_(self):
        pass
    @outer
    def zoo(self):
        print('hello zoo')
zoo = Zoo()
print(zoo.zoo.__name__)
zoo.zoo()

 可以看到类方法装饰器和函数装饰器,唯一的区别是多了一个默认的self参数,这是因为类方法本身比函数多一个参数。

2、装饰器的应用

Python 装饰器的应用比较广泛,大部分场景的公共处理逻辑都可以使用装饰器去简化。(使用上类似于 JAVA 中的注解)一般比较常见的场景比如:

  • 日志记录
  • 权限验证
  • 单例模式
  • 竞争资源管理
  • Fixture

2.1 装饰器在pytest中的使用@pytest.fixture 

        比如 conftest 胶水文件中可以写 driver 以及写数据库连接操作等,使用装饰器+生成器假设我们有一个需要连接数据库执行查询操作的测试用例集合。
        在每个测试用例执行前,我们需要先建立数据库连接,并在每个测试用例执行结束后,关闭数据库连接。这时,我们可以使用 @pytest.fixture 装饰器定义一个名为 db_conn 的fixture 函数,它返回一个数据库连接对象,然后在测试用例函数中通过参数引用该 fixture函数即可获得连接对象。
        我们可以非常方便地对测试用例进行初始化和清理工作,避免几余代码,并且可以重复利用测试代码和资源。
代码示例如下: 

import pytest
import psycopg2
@pytest.fixture(scope='function')
def db_conn():
    conn = psycopg2.connect(database="testdb",user="testuser",
password="testpass'host="localhost",port="5432")
    yield conn
    conn.close()

def test_query1(db_conn):
    cursor =db_conn.cursor()
    cursor.execute('SELECT * FROM table1')
    result = cursor.fetchall()
    assert len(result)>0

def test_query2(db_conn):
    cursor=db_conn.cursor()
    cursor.execute('SELECT * FROM table2')
    result = cursor.fetchall()
    assert len(result)>0

2.2 pytest中的@pytest.mark 

它可用于给测试用例打标签,方便统计测试结果和过滤测试用例。比如,给测试用例打上 slow、fast、smoke 等标签,可以通过 pytest 的命令行参数 pytest -m 进行选择性测试。

import pytest

@pytest.mark.slow
def test_case1():
    pass


@pytest.mark.fast
def test_case2():
    pass


@pytest.mark.smoke
def test_case3():
    pass

pytest .\1.py -m smoke 

 

如图,只有标记为smoke的被执行了 

2.3 @pytest.mark.paramsmetrize在pytest中的使用(参数化)

它可用于参数化测试用例,即对同一种情况下的不同输入进行测试,可以减少重复的测试代码和测试用例数量。

import pytest
@pytest.mark.parametrize('a, b,c',[(1,2,3),(4,5,9),(7,8, 15)])
def test add(a, b, c):
        assert a+b==C 

 2.4 pytest中的@pytest.hookimpl中的使用

它可以定义 pytest 的 hook 函数,hook 函数用于在 pytest 的执行过程中被调用,以处理测试收集、运行、报告等各个环节。
 

import pytest
@pytest.hookimpl
def pytest runtest call(item):
        print(f"test function fitem.name} is about to run...")

把这个函数放到 conftest 中就可以实现功能了

 每当我们跑一个用例,就会打印一些日志内容

2.5 python 的@property 装饰器的介绍与使用

python 的@property 是 python 的一种装饰器,是用来修饰方法的。

作用:
我们可以使用@property 装饰器来创建只读属性,@property 装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改。 

简而言之:

1.可以把方法变为属性

2.防止属性被修改

class DataSet(object):
    @property
    def method _with_property(self):
##含有@property
        return 15
    def method without property(self):##不含@property
        return 15
I= DataSet()
print(l.method with _property)
#加了@property 后,可以用调用属性的形式来调用方法,后面不需要加()
print(l.method without property())
#没有加@property,必须使用正常的调用方法的形式,即在后面加()

3、多线程编程思想 

1、如果你的测试用例是 I/O 密集型的,比如页面加载、数据输入等操作,那么使用多线程可以显著提高测试执行的效率。因为在等待I/O操作完成的时间内,可以切换到其他线程执行任务,避免浪费 CPU 资源,简单来说就是频繁输入加载等操作,就很适合多线程,不过要注意电脑的配置
2、如果你的测试用例需要在不同的浏览器或者不同的页面之间进行切换,那么使用多
线程可以避免在切换时出现页面卡顿或者响应延迟的问题。

3、如果除开这上面的操作,如果强行使用多线程开发,可能还会导致性能下降,因为需要频繁去调度 cpu,切换线程,线程间切换的开销可能会抵消掉并行处理所获得的性能提升

使用方法:使用 pytest-xdist 插件来实现多线程并发执行测试用例(自动分配每个线程要执行哪些测试用例)

当运行测试时,pytest-xdist 插件会自动将测试用例分发给多个线程并发执行,每个线程都可以独立打开一个网页运行测试用例,从而提高整体的执行效率。
使用 pytest 单线程运行测试用例:

pytest无头模式

在无头模式中,五个用例执行快了四秒,我为每一个用例都分配了一个线程去执行,这样会更快,因为会并发的去执行这五个测试用例。cpu不断的调度实现宏观的并发,微观实际上还是并行)
在有头模式中,打开了五个浏览器一起执行 88 个测试用例,相当于五个人一起执行测试用例,速度肯定是更快的,快了30s。(cpu不断的调度实现宏观的并发,微观实际上还是并行)
用法详解:
1、pytest-n 2:使用 2 个进程并行运行测试,如果有四个用例,1,3用例给第一个线程执行,2,4用例给第二个线程执行。
2、pytest -n auto:自动检测可用的 CPU 核心数量,并使用对应数量的进程并行运行测试。这是一种常用的设置,可以充分利用计算资源。
3、pytest -n 4-dist=loadfile:使用 4个进程并行运行测试,并使用"oadfile"分发插件进行测试运行。
使用 -n 参数,pytest 可以在多个进程中同时执行测试,从而加快整体测试运行时间,特别是在拥有多个 CPU 核心或处理器的计算机上。建议在实际使用时,根据自己的系统配置和测试需求,调整-n参数的值来获得最佳的性能和效果

4、数据驱动测试,yaml数据源 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2143271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据新视界 --大数据大厂之数据驱动决策:如何利用大数据提升企业竞争力

💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

3.信号量与互斥量

队列:用来传递数据 如果不想传递数据,只是"通知"呢? 这个时候,我们就可以使用"信号量","信号量"的本质:item_size等于 0 的队列 信号量里面有什么呢? 1.一个计数值 2.一个"队伍",就是一个链表:用来记录等待的对应信号量的任务 …

小阿轩yx-Prometheus监控系统部署

小阿轩yx-Prometheus监控系统部署 前言 Prometheus 由 Go 语言编写而成,采用 Pull 方式获取监控信息,并提供了多维度的数据模型和灵活的査询接口。Prometheus 不仅可以通过静态文件配置监控对象,还文持自动发现机制,能通过 Kube…

关于std::swap原理

swap 操作交换两个相同类型容器的内容。调用swap之后&#xff0c;两个容器中的元素将会 交换&#xff1a; vector<striong> svec1(10); //10个元素的vector vector<string> svec2(24); //24个元素的vector swap(svec1,svec2); 调…

红帽7—Mysql的源码编译

到官网选择源码进行安装 使用wget命令下载链接 下载安装后对文件包进行解压 [rootnginx ~]# tar zxf mysql-boost-5.7.44.tar.gz 安装cmake编译工具 [rootnginx ~]# yum install cmake 使用源码编译安装mysql [rootmysql-node10 mysql-5.7.44]# cmake \ -DCMAKE_INSTALL_PRE…

8.Lab Sevent —— Multithreading

首先切换到thread分支 git checkout thread make clean Uthread&#xff1a;switch between threads 为用户级线程系统设计上下文切换机制 xv6中已经放了两个文件&#xff1a; user/uthread.c和user/uthread_switch.S 以及一个规则&#xff1a;运行在Makefile中以构建uthre…

Linux:用户账号管理和组账号管理

用户账号管理 账号控制总述 用户账户 作用: 1.可以登陆操作系统 2.不同的用户具备不同的权限 唯一标识&#xff1a;UID&#xff08;编号从0开始的编号&#xff0c;默认最大60000&#xff09;zhangsan(UID 1200) 管理员root的UID&#xff1a;永远为0 系统用户&#xff08;为程…

django学习入门系列之第十点《A 案例: 员工管理系统9》

文章目录 12 管理员操作12.1 添加的界面集成12.2更改样式12.3验证密码 往期回顾 12 管理员操作 12.1 添加的界面集成 因为添加界面基本不用怎么改&#xff0c;所以可以直接集成进去 需要再次改动的地方 这样的话相当于直接在视图界面上直接传就行了&#xff0c;来提高复用率…

二十种编程语言庆祝中秋节

二十种编程语言庆祝中秋节 文章目录 二十种编程语言庆祝中秋节中秋快乐&#xff01;家人们 &#x1f973;一 Python二 C三 C四 Java五 C#六 Perl七 Go八 Asp九 PHP十 JavaScript十一 JavaScript HTML十二 Visual Basic十三 早期 VB十四 Visual C十五 Delphi十六 Shell十七 Cobo…

鸿蒙开发之ArkTS 界面篇 一

建好一个工程后&#xff0c;右侧可以预览&#xff0c;看到效果&#xff0c;效率十分可以&#xff0c;如图: State message: string 鸿蒙开发入门篇; 这个字符串改成什么&#xff0c;右侧就显示什么 Entry是类装饰器&#xff0c;可以简单的理解为程序入口的必须的装饰器&…

25届校招IQCAT思维能力自适应测验智鼎测评指南:题库获取、刷题策略与真题解析!

IQCAT思维能力自适应测验考试内容介绍 IOCAT思维能力自适应测验基于二因素智力理论&#xff0c;通过考察作答者的一般认知能力&#xff0c;预测其学习新知识、新技能以及理解、解决问题时的工作表现。IQCAT使用自适应测验技术&#xff0c;根据作答者的作答情况&#xff0c;从题…

shell脚本语法

shell脚本的变量 系统变量 系统变量是操作系统用来存储配置信息的变量&#xff0c;它们可以控制操作系统的行为和程序的运行环境。系统变量的种类和内容取决于操作系统的类型和版本。以下是一些常见的系统变量类别和它们可能包含的内容&#xff1a; 环境变量&#xff1a;这些…

OpenCV calcHist()函数及其用法详解

OpenCV calcHist()函数原型共有三个&#xff0c;如下&#xff1a; 该函数计算一个或多个数组的直方图。用于递增直方图箱的元组的元素取自同一位置的相应输入数组。 函数参数&#xff1a; images 源&#xff08;图像&#xff09;数组。它们都应具有相同的深度、CV_8U、CV_16U…

YOLOv8改进 - 注意力篇 - 引入CBAM注意力机制

一、本文介绍 作为入门性第一篇&#xff0c;这里介绍了CBAM注意力在YOLOv8中的使用。包含CBAM原理分析&#xff0c;CBAM的代码、CBAM的使用方法、以及添加以后的yaml文件及运行记录。 二、CBAM原理分析 CBAM官方论文地址&#xff1a;CBAM论文 CBAM的pytorch版代码&#xff…

Gateway网关的实现

API网关 网关路由必须支持负载均衡&#xff0c;服务列表是从注册中心拉取的客户端发出请求的URL指向的是网关&#xff0c;URL还必须要包含目标信息网关收到URL&#xff0c;通过一定的规则&#xff0c;要能识别出交给哪个实例去处理网关有能力对请求响应进行修改 引入依赖包 …

图论算法(DFS/BFS/拓扑排序/最短路/最小生成树/二分图/基环树/欧拉路径)

DFS 基础 BFS 基础 Leetcode 815. 公交路线 思路&#xff1a; class Solution { public:int numBusesToDestination(vector<vector<int>>& routes, int source, int target) {// 记录经过车站x的公交车编号 hashunordered_map<int, vector<int>> …

frp内网穿透功能使用教程

frp 是一款高性能的反向代理应用&#xff0c;专注于内网穿透。它支持多种协议&#xff0c;包括 TCP、UDP、HTTP、HTTPS 等&#xff0c;并且具备 P2P 通信功能。使用 frp&#xff0c;您可以安全、便捷地将内网服务暴露到公网&#xff0c;通过拥有公网 IP 的节点进行中转。 文档地…

Python3网络爬虫开发实战(15)Scrapy 框架的使用(第一版)

文章目录 一、Scrapy 框架介绍1.1 数据流1.2 项目结构1.3 Scrapy 入门 二、Selector 解析器2.1 XPath 和 CSS 选择器2.2 信息提取2.3 正则提取 三、Spider 的使用3.1 Spider 运行流程3.2 Spider 类分析3.3 Request3.4 Response 四、Download Middleware 的使用4.1 process_requ…

55.【C语言】字符函数和字符串函数(strstr函数)

11.strstr函数 *简单使用 strstr: string string cplusplus的介绍 点我跳转 翻译: 函数 strstr const char * strstr ( const char * str1, const char * str2 ); 或另一个版本char * strstr ( char * str1, const char * str2 ); 寻找子字符串 返回指向第一次出现在字…