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

UI自动化之混合框架

什么是混合框架,混合框架就是将数据驱动与关键字驱动结合在一起,主要用来回归业务主流程,将核心流程串联起来。

上一篇我们写到了关键字驱动框架,关键字驱动框架是针对一个业务场景的单条测试用例的。

我们以163邮箱的登录到创建联系人这个流程为例,来看看混合框架是怎样的。

首先准备一个存放测试用例和数据的excel文件,文件内容如下:

测试用例的sheet页:case

mock表示这条测试用例我们需要用到的框架模型,key表示关键字,data表示数据

step_sheet表示这条用例我们需要用到的关键字驱动的sheet页名称

data_sheet表示这条用例我们需要用到的数据驱动的sheet页名称

login_step页:

add_person_step页:添加联系人的步骤

add_person_data页:添加联系人所需要用到的数据

excel的准备工作就完成了,接下来看代码:

首先是项目目录:只写了简单的几个目录,其他的目录在pageobject三层架构中写过,可以参考,都是一样的。

Setting文件夹的Config.py文件:

# Config.py
import osBase_Dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 测试数据文件
Test_Data_Path = os.path.join(Base_Dir, 'TestData')

Util文件夹的find_ele.py文件:

# find_ele.py
from selenium.webdriver.support.wait import WebDriverWaitdef find_element(driver, location_type, location_express):'''查找控件元素'''try:driver = WebDriverWait(driver, 20).until(lambda driver:driver.find_element(location_type, location_express))return driverexcept Exception as e:raise edef find_elements(driver, location_type, location_express):'''查找元素组'''try:driver = WebDriverWait(driver, 20).until(lambda driver:driver.find_elements(location_type, location_express))return driverexcept Exception as e:raise e

Util文件夹的excel_parse.py文件:读取excel的内容

# excel_parse.py
from Setting.Config import Test_Data_Path
from openpyxl import load_workbookclass ExcelParse:def __init__(self):self.workbook = None# self.sheet = Nonedef load_workbook(self, filename):'''加载文件'''try:self.workbook = load_workbook(filename)except Exception as e:raise edef get_sheet(self, sheetname):'''获取sheet页'''try:# self.sheet = self.workbook[sheetname]return self.workbook[sheetname]except Exception as e:raise edef get_row_num(self, sheet):'''返回行数'''# return self.sheet.max_rowreturn sheet.max_rowdef get_col_num(self, sheet):'''返回列数'''# return self.sheet.max_columnreturn sheet.max_columndef get_cell_value(self, sheet, row, col):'''返回某一单元格的值'''# return self.sheet.cell(row=row, column=col).valuereturn sheet.cell(row=row, column=col).valuedef get_row_value(self, sheet, row):'''返回某一行的值'''try:col = self.get_col_num(sheet)data = []for i in range(1, col+1):data.append(self.get_cell_value(sheet, row, i))return dataexcept Exception as e:raise edef write_cell(self, sheet, row, col, filename, content):'''单元格赋值'''try:# self.sheet.cell(row=row, column=col, value=content)sheet.cell(row=row, column=col, value=content)self.workbook.save(filename)except Exception as e:raise eif __name__ == '__main__':execl = ExcelParse()execl.load_workbook(Test_Data_Path + '/test_data.xlsx')sheet = execl.get_sheet('case')# execl.get_sheet('login')res = execl.get_row_value(sheet, 2)print(res)

Util文件夹的elementAction.py文件:执行动作的封装

# elementAction.py
import timefrom selenium import webdriver
from Util.find_ele import find_element, find_elementsdriver = Nonedef open_browse(browser_name, *args):'''打开浏览器'''global drivertry:if browser_name.lower() == 'chrome':driver = webdriver.Chrome()elif browser_name.lower() == 'firefox':driver = webdriver.Firefox()else:driver = webdriver.Ie()except Exception as e:raise edef get_url(url, *args):'''打开网址'''try:driver.get(url)except Exception as e:raise edef max_window(*args):'''窗口最大化'''try:driver.maximize_window()except Exception as e:raise edef switch_frame(location_type, location_express, *args):'''切换iframe'''try:frame = find_element(driver, location_type, location_express)driver.switch_to.frame(frame)except Exception as e:raise edef input_content(location_type, location_express, content, *args):'''定位输入框,输入内容'''try:find_element(driver, location_type, location_express).send_keys(content)except Exception as e:raise edef input_subject(location_type, location_express, input_conetnt, *args):'''定位输入框,输入内容'''try:# location_express的值为:location_express, index = location_express.split(',')find_elements(driver, location_type, location_express)[int(index)].send_keys(input_conetnt)except Exception as e:raise edef switch_default(*args):'''返回默认iframe'''try:driver.switch_to.default_content()except Exception as e:raise edef click(location_type, location_express, *args):'''点击操作'''try:find_element(driver, location_type, location_express).click()except Exception as e:raise edef assert_title(title, *args):'''断言title是否正确'''try:assert title in driver.titleexcept Exception as e:raise edef close_browse():'''关闭浏览器'''driver.quit()def sleep(sec):'''等待'''time.sleep(sec)if __name__ == '__main__':open_browse('chrome')get_url('http://mail.163.com')max_window()switch_frame('tag name', 'iframe')input_content('name', 'email', 'YM_yimin')input_content('name', 'password', 'yimin19960930')click('id', 'dologin')assert_title('网易')

Util文件夹的common.py文件:封装拼接的执行动作函数

# common.py
def generate_method_express(location_type, location_express, key_word, operate_data):# location_type, location_express为空,operate_data不为空if key_word and operate_data and location_type is None and location_express is None:# 判断操作值的类型if isinstance(operate_data, int):method_express = key_word + '(' + str(operate_data) + ')'else:method_express = key_word + "('" + operate_data + "')"# print(method_express)# 只有关键字有值,其他的都为空,比如:max_window, close_browseelif key_word and operate_data is None and location_type is None and location_express is None:method_express = key_word + '()'# print(method_express)# location_type,location_express不为空,operate_data为空elif key_word and location_type and location_express and operate_data is None:method_express = key_word + "('" + location_type + "','" + location_express + "')"# print(method_express)# 都不为空else:if isinstance(operate_data, int):method_express = key_word + "('" + location_type + "','" + location_express + "'," + str(operate_data) + ")"else:method_express = key_word + "('" + location_type + "','" + location_express + "','" + operate_data + "')"print(method_express)return method_express

TestScript文件夹下的add_contractor.py文件:添加联系人的测试用例执行

# 添加联系人
import timefrom Util.common import generate_method_express
from Util.excel_parse import ExcelParse
from Setting.Config import Test_Data_Path
from Util.elementAction import *
from Util import elementAction
from Util.find_ele import find_elementdef add_contractors(excel, stepSheet, dataSheet):'''添加联系人'''# 数据源行数data_row_nums = excel.get_row_num(dataSheet)# 步骤行数step_row_nums = excel.get_row_num(stepSheet)# 成功的步骤数success_record = 0# 数据驱动sheet页中需要执行的行数need_run_record = 0# 遍历数据驱动sheet页中的数据for i in range(2, data_row_nums):# 判断数据驱动sheet页的数据是否需要执行if excel.get_cell_value(dataSheet, i, 6).lower() == 'y':need_run_record += 1# 将这一行的数据全部拿出来name = excel.get_cell_value(dataSheet, i, 1)   # 姓名email = excel.get_cell_value(dataSheet, i, 2)   # 邮箱is_star = excel.get_cell_value(dataSheet, i, 3)   # 是否星标phone = excel.get_cell_value(dataSheet, i, 4)    # 电话号码remarks = excel.get_cell_value(dataSheet, i, 2)   # 备注success_step = 0     # 记录每行数据成功的步骤数# 编辑关键字驱动sheet页中的步骤for j in range(2, step_row_nums):# 获取关键字驱动sheet页中的每行数据step_desc = excel.get_cell_value(stepSheet, j, 2)         # 步骤描述location_type = excel.get_cell_value(stepSheet, j, 3)     # 定位方式location_express = excel.get_cell_value(stepSheet, j, 4)   # 定位方式表达式keyword = excel.get_cell_value(stepSheet, j, 5)           # 关键字operate_value = excel.get_cell_value(stepSheet, j, 6)      # 操作值# 当操作值是变量的时候,要引用数据源(数据驱动sheet页)中的数据# operate_value的值是字符串,并且以${开头,}结尾, 例如operate_value='${name}'if isinstance(operate_value, str) and operate_value.startswith('${') and operate_value.endswith('}'):# 把operate_value中的变量名截取出来operate_value = eval(operate_value[2:operate_value.index('}')])# 组装函数,拼接每个步骤的执行动作函数func_express = generate_method_express(location_type, location_express, keyword, operate_value)# 当step_desc为星标是否选择时,当operate_value等于Y(即执行点击操作),选中星标,当operate_value等于Y,不选中星标(即不执行点击操作)# func_express = click(location_type, location_express, 'Y/N')if operate_value != 'no_star':# 执行选中星标,点击操作try:eval(func_express)except Exception as e:raise eelse:# 执行选中星标操作,没有异常,成功步骤+1success_step += 1else:# 不执行选中星标操作,要记录成功步骤数success_step += 1# 判断成功步骤数,与关键字驱动sheet页的步骤数是否相等if success_step+1 == step_row_nums:# 成功步骤数+1 等于 关键字驱动sheet页的行数, 成功的数据+1success_record += 1# 将成功的结果写入数据驱动sheet页对应的单元格excel.write_cell(dataSheet, i, 7, Test_Data_Path+'/test_data.xlsx', 'pass')else:excel.write_cell(dataSheet, i, 7, Test_Data_Path + '/test_data.xlsx', 'fail')# 数据驱动sheet页中的所有数据全部轮训执行完之后# 判断成功记录数success_record 和 需要执行的数据need_run_record  相等,则说明该测试用例执行成功if success_record == need_run_record:return 'Pass'else:return 'Fail'if __name__ == '__main__':from selenium import webdriverdriver = webdriver.Chrome()driver.get('http://mail.163.com')frame = find_element(driver, 'tag name', 'iframe')driver.switch_to.frame(frame)find_element(driver, 'name', 'email').send_keys('test123')find_element(driver, 'name', 'password').send_keys('a123456')find_element(driver, 'id', 'dologin').click()time.sleep(5)elementAction.driver = driverexecl = ExcelParse()execl.load_workbook(Test_Data_Path + '/test_data.xlsx')step_sheet = execl.get_sheet('add_person_step')data_sheet = execl.get_sheet('add_person_data')add_contractors(execl,step_sheet, data_sheet)

TestScript文件夹的test_login_add_send.py文件:读取case页的测试用例,进行执行

# test_login_add_send.py
from Util.excel_parse import ExcelParse
from Setting.Config import Test_Data_Path
from TestScript.add_contractor import add_contractors
from Util.common import generate_method_expressdef test_loginAndAddAndSend():try:# 获取数据文件case中的内容excel = ExcelParse()excel.load_workbook(Test_Data_Path + '/test_data.xlsx')case_sheet = excel.get_sheet('case')    # 获取测试用例sheet页case_nums = excel.get_row_num(case_sheet)     # case的总行数# 遍历case中的数据for i in range(2, case_nums+1):# 判断该用例是否要执行if excel.get_cell_value(case_sheet, i, 7) == 'y':# 获取用例名称case_name = excel.get_cell_value(case_sheet, i, 2)# 框架类型frame_mode = excel.get_cell_value(case_sheet, i, 4)# 步骤sheet名step_sheet_name = excel.get_cell_value(case_sheet, i, 5)stepsheet = excel.get_sheet(step_sheet_name)   # 获取步骤sheet页if frame_mode == 'data':# 如果框架类型为data,获取数据sheet名data_sheet_name = excel.get_cell_value(case_sheet, i, 6)# 分别获取两个sheet,作为参数传入datasheet = excel.get_sheet(data_sheet_name)result = None# 调用对应的方法,即添加联系人的方法if case_name == 'add_person':result = add_contractors(excel, stepsheet, datasheet)if result == 'Pass':excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Pass')else:excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Fail')elif frame_mode == 'key':# 获取步骤数step_nums = excel.get_row_num(stepsheet)# 记录成功的步骤数success_step_num = 0for j in range(2, step_nums+1):# 步骤描述step_desc = excel.get_cell_value(stepsheet, j, 2)location_type = step_desc = excel.get_cell_value(stepsheet, j, 3)location_express = step_desc = excel.get_cell_value(stepsheet, j, 4)key_word = excel.get_cell_value(stepsheet, j, 5)operate_value = step_desc = excel.get_cell_value(stepsheet, j, 6)# 构建函数表达式func_express = generate_method_express(location_type, location_express, key_word, operate_value)# 执行函数, 不抛出异常就认为执行成功try:print(f'开始执行 {step_desc}')eval(func_express)except Exception as e:print(f'执行{step_desc}发生异常{e}')# 某一步发生异常,则该用例执行失败,将失败结果写入测试用例(case)sheet页excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Fail')else:success_step_num += 1# 执行成功步骤数+1 = 步骤总数,用例执行成功if success_step_num+1 == step_nums:# 写入成功excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Pass')else:excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Skip')except Exception as e:raise e

最后执行test_login_add_send.py文件,即实现了混合框架。

相关文章:

UI自动化之混合框架

什么是混合框架,混合框架就是将数据驱动与关键字驱动结合在一起,主要用来回归业务主流程,将核心流程串联起来。 上一篇我们写到了关键字驱动框架,关键字驱动框架是针对一个业务场景的单条测试用例的。 我们以163邮箱的登录到创建…...

SQL创建用户-非DM8.2环境(达梦数据库)

DM8:达梦数据库SQL创建用户-非DM8.2环境 环境介绍 环境介绍 在没有图形化界面,或者想快速创建用户,可以使用一下SQL语句;将其中的 CESHI 替换为要创建的用户名即可,默认创建了数据表空间,索引表空间,文件大…...

Thread类中run和start的区别

答:调用线程类中的 start 方法,才开始创建并启动线程,而线程被回收,则是要执行完线程的入口方法(对于主线程来说,则是要执行完 main 方法),这里要回收线程则是要将(&…...

ElementUI浅尝辄止35:Checkbox 多选框

一组备选项中进行多选 1.如何使用? 单独使用可以表示两种状态之间的切换,写在标签中的内容为 checkbox 按钮后的介绍。 //在el-checkbox元素中定义v-model绑定变量,单一的checkbox中,默认绑定变量的值会是Boolean,选…...

讲讲如何用IDEA开发java项目——本文来自AI创作助手

使用IDEA开发Java项目,您可以按照以下步骤进行操作: 下载并安装IntelliJ IDEA 您可以从JetBrains官网下载并安装最新版的IntelliJ IDEA。 创建项目 启动IDEA,在欢迎界面中选择“Create New Project”或者在主菜单中选择“File”->“Ne…...

Kafka3.0.0版本——消费者(Range分区分配策略以及再平衡)

目录 一、Range分区分配策略原理1.1、Range分区分配策略原理的示例一1.2、Range分区分配策略原理的示例二1.3、Range分区分配策略原理的示例注意事项 二、Range 分区分配策略代码案例2.1、创建带有4个分区的fiveTopic主题2.2、创建三个消费者 组成 消费者组2.3、创建生产者2.4、…...

WeiTools

目录 1.1 WeiTools 1.2 getTime 1.3 getImageView 1.4 StringEncode 1.4.1 // TODO Auto-generated catch block WeiTools package com.shrimp.xiaoweirobot.tools;...

目标检测数据集:医学图像检测数据集(自己标注)

1.专栏介绍 ✨✨✨✨✨✨目标检测数据集✨✨✨✨✨✨ 本专栏提供各种场景的数据集,主要聚焦:工业缺陷检测数据集、小目标数据集、遥感数据集、红外小目标数据集,该专栏的数据集会在多个专栏进行验证,在多个数据集进行验证mAP涨点明显,尤其是小目标、遮挡物精度提升明显的…...

【系统设计系列】数据库

系统设计系列初衷 System Design Primer: 英文文档 GitHub - donnemartin/system-design-primer: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards. 中文版: https://github.com/donnemarti…...

mp4压缩视频不改变画质?跟我这样压缩视频大小

在当今数字化时代,视频文件变得越来越普遍,然而,这些文件通常都很大,给存储和传输带来了困难,为了解决这个问题,许多人都希望将视频压缩得更小,而又不牺牲画质,下面就来看看具体应该…...

AQS同步队列和等待队列的同步机制

理解AQS必须要理解同步队列和等待队列之间的同步机制,简单来说流程是: 获取锁失败的线程进入同步队列,成功的占用锁,占锁线程调用await方法进入条件等待队列,其他占锁线程调用signal方法,条件等待队列线程进…...

vue3实现无限循环滚动的方法;el-table内容无限循环滚动的实现

需求&#xff1a;vue3实现一个div内的内容无限循环滚动 方法一&#xff1a; <template><div idcontainer><div class"item" v-foritem in 5>测试内容{{{ item }}</div></div> </template><script setup> //封装一个方法…...

Windows 安装 MariaDB 数据库

之前一直使用 MySQL&#xff0c;使用 MySQL8.0 时候&#xff0c;占用内存比较大&#xff0c;储存空间好像也稍微有点大&#xff0c;看到 MariaDB 是用来代替 MySQL 的方案&#xff0c;之前用着也挺得劲&#xff0c;MySQL8.0 以上好像不能去导入低版本的 sql&#xff0c;或者需要…...

RK3568-mpp(Media Process Platform)媒体处理软件平台

第一章 MPP 介绍 1.1 概述 瑞芯微提供的媒体处理软件平台(Media Process Platform,简称 MPP)是适用于瑞芯微芯片系列的通用媒体处理软件平台。 该平台对应用软件屏蔽了芯片相关的复杂底层处理,其目的是为了屏蔽不同芯片的差异,为使用者提供统一的视频媒体处理接口(Medi…...

【ModelSim】使用终端命令行来编译、运行Verilog程序,创建脚本教程

▚ 01 ModelSim命令解说 &#x1f4e2; 这些命令是 ModelSim 中常用的命令&#xff0c;用于创建库、编译源代码和启动仿真。 &#x1f514; 在使用这些命令之前&#xff0c;你需要在 ModelSim 的命令行界面或脚本中执行 vlib 命令来创建一个库&#xff0c;然后使用 vlog 命令…...

腾讯云网站备案详细流程_审核时间说明

腾讯云网站备案流程先填写基础信息、主体信息和网站信息&#xff0c;然后提交备案后等待腾讯云初审&#xff0c;初审通过后进行短信核验&#xff0c;最后等待各省管局审核&#xff0c;前面腾讯云初审时间1到2天左右&#xff0c;最长时间是等待管局审核时间&#xff0c;网站备案…...

HTTP介绍:一文了解什么是HTTP

前言&#xff1a; 在当今数字时代&#xff0c;互联网已经成为人们生活中不可或缺的一部分。无论是浏览网页、发送电子邮件还是在线购物&#xff0c;我们都离不开超文本传输协议&#xff08;HTTP&#xff09;。HTTP作为一种通信协议&#xff0c;扮演着连接客户端和服务器的重要角…...

动态规划之子数组系列

子数组系列 1. 环形⼦数组的最⼤和2. 乘积最大子数组3. 等差数列划分4. 最长湍流子数组5. 单词拆分6. 环绕字符串中唯⼀的子字符串 1. 环形⼦数组的最⼤和 1.题目链接&#xff1a;环形⼦数组的最⼤和 2.题目描述&#xff1a;给定一个长度为 n 的环形整数数组 nums &#xff0c…...

LeetCode(力扣)332.重新安排行程Python

LeetCode332.重新安排行程 题目链接代码 题目链接 https://leetcode.cn/problems/reconstruct-itinerary/ 代码 class Solution:def backtracking(self, tickets, used, cur, result, path):if len(path) len(tickets) 1:result.append(path[:])return Truefor i, ticket…...

Pytho 从列表中创建字典 (dict.fromkeys()的问题)

问题起因&#xff1a;想在代码中通过已有的列表创建一个字典&#xff0c;但是又不想写循环&#xff0c;更不想手动填&#xff0c;所以用到了字典对象的fromkeys()方法 。 先以一个简单的例子介绍一下该方法&#xff1a; a ["A", "B", "C", &qu…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...