当前位置: 首页 > news >正文

UI自动化测试重点思考(下)--装饰器/生成器/夹具的使用/描述符的作用/ddt驱动/多线程

UI自动化测试重点思考--装饰器

  • 装饰器
    • 装饰器定义
    • 装饰器代码示例
    • 装饰器的执行
    • 如何将装饰器融合到pytest框架里面
  • 生成器
    • 创建生成器
    • 生成器的定义
    • 如何将生成器融合到pytest框架里面
  • fixture(夹具)使用
    • pytest fixture 中 scope 参数的详细解释
  • 描述符的总结
    • 描述符的定义
    • 描述符的作用
  • ddt数据驱动
    • 简单示例
    • 升级示例
  • 多线程
    • 安装pytest-xdist 插件
    • 采用多线程编程

装饰器

装饰器定义

装饰器是一个函数A,函数A的传参是函数B,且函数A内部还有一个函数C,且函数A返回一个函数C,函数C是包含函数B的。

装饰器代码示例

def my_decorator(func):def wrapper():print("Something is happening before the function is called.")func()print("Something is happening after the function is called.")return wrapper@my_decorator
def say_hello():print("Hello!")say_hello()

在这个例子中,my_decorator 是一个装饰器函数,它接受一个函数作为参数。wrapper 函数是由装饰器内部定义的一个新函数,它包裹了原始的 say_hello 函数,并添加了额外的功能。当调用 say_hello() 时,实际上是调用了 wrapper 函数,从而触发了装饰器中定义的操作。

装饰器的执行

在这里插入图片描述

  1. 当 Python 解释器执行到 @my_decorator 时,它会立即将被装饰的函数 say_hello 传递给 my_decorator 函数,相当于执行了 say_hello = my_decorator(say_hello)
  2. 在 my_decorator 函数内部,它定义了一个内部函数 wrapper,该函数包含了在被装饰函数调用前后需要执行的逻辑。
  3. 当调用 say_hello() 时,实际上是调用了 wrapper() 函数,因为 say_hello 已经被重新指向了 wrapper 函数。
  4. 在 wrapper 函数内部,首先会执行装饰器定义的前置逻辑,然后调用被装饰的函数 func(),即调用原始的 say_hello 函数。
  5. 在调用完被装饰函数后,继续执行 wrapper 函数中的后置逻辑

如何将装饰器融合到pytest框架里面

1.全局管理 driver,运行测试用例的时候先调用 driver 传入测试用例中,测试用例就可以使用 driver来操作浏览器了。
2.实现执行测试用例之前先登录或者先打开网址,执行测试用例之后再自动登出的操作。

生成器

创建生成器

  • 生成器推导式
gen = (x ** 2 for x in range(1, 6))
  • 含有yield关键字
def squares(n):for i in range(1, n + 1):yield i ** 2print("这里被挤出了一个糖")
gen=squares(5)

定义了一个名为 squares 的函数,该函数接受一个整数 n 作为参数。在函数内部,使用 yield 语句来生成从 1 到 n 的整数的平方值,并在最后打印一条信息 “这里被挤出了一个糖”。

生成器的定义

1.只要是实现了yield关键字的函数都是一个生成器
2.生成器的特点是,当调用者执行到yield就会卡住,然后把yield后面的参数返回给调用者
3.当接收到next()函数的命令的时候才会执行yield关键字下面的代码

如何将生成器融合到pytest框架里面

1.自动登录登出中要使用生成器
实现了执行测试用例之前先执行前置操作【登录】【因为有装饰器】直到代码运行到有 yield 关键字的时候才会卡住,当执行完测试用例之后,pytest 自动调用 next 函数,才会去执行 yield 关键字后的后置操作【登出】。

fixture(夹具)使用

pytest fixture 中 scope 参数的详细解释

Scope 参数值描述
function每个测试函数都会调用一次 fixture 函数,并且在测试函数执行完毕后立即销毁。
class在测试类中的所有测试方法之间共享 fixture,fixture 在第一个测试方法运行前创建,在最后一个测试方法运行后销毁。
module在整个测试模块中共享 fixture,fixture 在第一个测试函数运行前创建,在最后一个测试函数运行后销毁。
session在整个 pytest 会话期间共享 fixture,fixture 在 pytest 启动时创建,在 pytest 结束时销毁。

描述符的总结

描述符的定义

描述符是实现了特定协议的类,它至少包含 get()、set() 和 delete() 中的一个方法。

描述符的作用

描述符可以用于控制对类的属性的访问、修改和删除,允许你在属性被访问、修改或删除时执行自定义的逻辑。

在这里插入图片描述

class PageElement:def __get__(self, instance, owner):print("Getting the value")return instance.__dict__.get(self.attr_name, None)def __set__(self, instance, value):print("Setting the value")instance.__dict__[self.attr_name] = valuedef __delete__(self, instance):print("Deleting the value")del instance.__dict__[self.attr_name]class Page:element = PageElement()def __init__(self):self.element = None@propertydef element(self):return self._element@element.setterdef element(self, value):self._element = value# 示例用法
page = Page()
page.element = "Hello"  # 设置属性值,调用 PageElement.__set__()
print(page.element)     # 获取属性值,调用 PageElement.__get__()
del page.element        # 删除属性值,调用 PageElement.__delete__()

ddt数据驱动

简单示例

import pytest
import time@pytest.mark.smoke
@pytest.mark.parametrize('username, password', [('user1', 'DasSWOLd'),('user2', 'pass2'),('wzz', '12345')
])
def test_001(self, drivers, username, password):zhufeng = ZhuifengIndexPage(drivers)zhufeng.input_account(username)zhufeng.input_password(password)zhufeng.click_login_button()time.sleep(3)
  1. @pytest.mark.smoke:是一个 pytest 的标记,用于标记测试用例为 smoke 测试,表示这是一个简单的冒烟测试,主要验证系统的基本功能。
  2. @pytest.mark.parametrize(‘username, password’, […]):是 pytest 提供的一个装饰器,用于为测试用例提供多组参数数据。
  3. 测试用例 test_001(self, drivers, username, password):这是一个测试方法,其参数包括 drivers、usernausername 和 password 是测试数据,由 @pytest.mark.parametrize 提供。me 和 password。
    在这里插入图片描述

升级示例

def read_csv_file(file_path):"""生成器方式去读取csv里面的数据来做数据驱动测试,yield关键字来控制一行一行的读取字典里面的内容(字典里面的数据是隐形的,还未产生,就和奶糖盒子一样的道理)"""with open(file_path, 'r', newline='') as file:reader = csv.DictReader(file)  # 这是一个迭代器对象,把每次读取出来的数据都放到字典里面存起来,下面用一个for循环一次一次的去读取字典里面的数据,确保不会一次性将所有的数据读取到内存中。for row in reader:  # 如过下面没有生成器,那么这里直接全部数据都遍历一遍,如果有生成器就会卡住,一个一个来,接收到next方法才会读取下一行。yield row['username'], row['password']@pytest.mark.smoke
@pytest.mark.parametrize('username, password', read_csv_file(r'data/data.csv'))
def test_001(drivers, username, password):zhufeng = zhuifeng_index_page(drivers)zhufeng.input_account = usernamezhufeng.input_password = password# zhufeng.log_in_button.click()zhufeng.click_log_in_button# assert drivers.current_url == 'https://exam.wzzz.fun'

1.read_csv_file 函数:

  • 这是一个生成器函数,用于逐行读取 CSV 文件中的数据。使用 yield
    关键字,每次从文件中读取一行数据,并返回一个包含用户名和密码的元组。
  1. @pytest.mark.parametrize(‘username, password’, read_csv_file(r’data/data.csv’)):
  • 使用 @pytest.mark.parametrize 装饰器标记测试用例,并提供了多组用户名和密码的数据源。
  • 数据源来自于 read_csv_file 函数返回的生成器,通过调用 read_csv_file 函数来读取 CSV文件中的数据,并将其作为参数传递给测试用例。
    3.def test_001(drivers, username, password):
  • 在测试方法中,首先创建了一个 zhufeng_index_page 对象,然后输入了用户名和密码,并点击了登录按钮(注释掉的部分)
  • 这个测试方法会被 @pytest.mark.parametrize 多次调用,每次调用时传入不同的用户名和密码数据。
    在这里插入图片描述

多线程

安装pytest-xdist 插件

pip install pytest-xdist

采用多线程编程

1、可以使用 threading 线程来指定要并发执行的测试用例,但是用例数量一旦多了,就不好去人工分配哪一个线程执行那部分用例,这时候可以使用插件 pytest-xdist,执行 pytest-n5就好了,使用多少个线程并发执行还是得看电脑性能如何,一般使用10~20 个线程为最佳,在自己电脑上就使用5个线程就好了。
2、多线程并发执行用例,相当于多个人同时进行测试,宏观上是这样的,不过微观上对于 cpu 都是串行的,只是调度每一个线程的速度非常快,看起来是并发的而己,因为只有一个cpu,同一时刻,只能执行一个线程,如果有多个cpu 才能真正意义上实现多个测试用例并发执行,不过对于测试而言,无伤大雅,我们了解原理即可,我们主要重在使用。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 数据结构1
  • 如何快速开启一个项目-ApiHug - API design Copilot
  • 如何使用群晖Synology Drive结合cpolar内网穿透实现同步Obsidian笔记文件
  • Unity UI 优化技巧
  • 论文笔记:Large Language Models as Analogical Reasoners
  • 计算机网络:数据链路层 - CSMA/CD协议
  • 技术突破还是情感寄托?AI克隆人技术的伦理之辨
  • 如何使用宝塔面板搭建MySQL数据库并实现无公网IP远程访问
  • uniapp引入微信小程序版本VantUI,使用VantUI的自定义tabbar,并解决自定义tabbar出现闪烁的情况
  • 代码随想录阅读笔记-二叉树【二叉搜索树转换为累加树】
  • 用vue.js写案例——ToDoList待办事项 (步骤和全码解析)
  • React - 你使用过高阶组件吗
  • WKWebView的使用
  • 安卓远离手机app
  • 自然语言处理-词向量模型-Word2Vec
  • @jsonView过滤属性
  • 【EOS】Cleos基础
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • 230. Kth Smallest Element in a BST
  • Angular4 模板式表单用法以及验证
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • idea + plantuml 画流程图
  • iOS | NSProxy
  • JS专题之继承
  • Nacos系列:Nacos的Java SDK使用
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • 从0到1:PostCSS 插件开发最佳实践
  • 记录:CentOS7.2配置LNMP环境记录
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 深度解析利用ES6进行Promise封装总结
  • 深入浅出Node.js
  • 数据结构java版之冒泡排序及优化
  • 详解NodeJs流之一
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • #include到底该写在哪
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (33)STM32——485实验笔记
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (算法)区间调度问题
  • (一)Thymeleaf用法——Thymeleaf简介
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • ***利用Ms05002溢出找“肉鸡
  • .bashrc在哪里,alias妙用
  • .htaccess 强制https 单独排除某个目录
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .net 中viewstate的原理和使用