UI自动化测试示例:python+pytest+selenium+allure

ops/2024/10/17 18:17:14/

重点应用是封装、参数化:

比如在lib文件夹下,要存储封装好的方法和必要的环境变量(指网址等)

1.cfg.py:封装网址和对应的页面

python">SMP_ADDRESS = 'http://127.0.0.1:8234'SMP_URL_LOGIN        = f'{SMP_ADDRESS}/login.html'
SMP_URL_DEVICE_MODEL = f'{SMP_ADDRESS}/index.html#/devicemodel'
SMP_URL_SERVICE_RULE = f'{SMP_ADDRESS}/index.html#/svcrule'

二、登录部分 

2.1 lib.py-登录模块的封装

主要就是输入账号名和密码进行测试。 

python">from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
import time
from lib.cfg import *class SMP_UI:def __init__(self):options = webdriver.ChromeOptions()#排除一些不需要的日志输出。options.add_experimental_option( 'excludeSwitches', ['enable-logging'])self.wd = webdriver.Chrome(options=options)self.wd.implicitly_wait(3) #隐式等待时间为5秒,等待元素加载完成#登录模块测试def login(self, username, password):self.wd.get(SMP_URL_LOGIN) #打开登录网址#time.sleep(1)#sleep方便观察if username is not None:self.wd.find_element(By.ID, 'username').send_keys(username)if password is not None:self.wd.find_element(By.ID, 'password').send_keys(password)self.wd.find_element(By.ID, 'loginBtn').click()#点击登录按钮smpUI = SMP_UI()

2.2自动化测试脚本代码-登录

from selenium.webdriver.common.by import By
import time,pytest
from lib.webUI_smp import smpUIdef test_SMP_login_001():#正确账号和密码smpUI.login('byhy','sdfsdf' )nav = smpUI.wd.find_elements(By.TAG_NAME, 'nav') #登陆后就可以查看nav了,有信息代表登陆成功assert nav != []@pytest.fixture
def clearAlert():yieldtry:smpUI.wd.switch_to.alert.accept()except Exception as e:print(e)@pytest.mark.parametrize('username, password, expectedalert', [(None, 'sdfsdf', '请输入用户名'),#空用户名('byhy', None, '请输入密码'),#空密码('byhy', 'sdfsd',   '登录失败: 用户名或者密码错误'),#少输入密码('byhy', 'sdfsdff', '登录失败: 用户名或者密码错误'),#多输入密码('byh', 'sdfsdf',   '登录失败: 用户名不存在'),#少输入用户名('byhyy', 'sdfsdf', '登录失败: 用户名不存在'),#多输入用户名])
def test_SMP_login_002(username, password, expectedalert, clearAlert):smpUI.login(username, password)smpUI.wd.implicitly_wait(5)#隐式等待alert = smpUI.wd.switch_to.alert.textassert alert == expectedalert #对弹出框进行断言对比

三、商品部分

3.1 lib.py-商品服务模块的封装

主要就是添加商品、删除商品等,输出第一页的第一条的值(检查返回值) 

python">    #添加设备模块检测def add_device_model(self, devType, name, desc):# 实例化选择框做为对象select = Select(smpUI.wd.find_element(By.ID, "device-type"))# 选择对应列表中的种类select.select_by_visible_text(devType)#清除填充框后填-设备型号ele = smpUI.wd.find_element(By.ID, 'device-model')ele.clear()ele.send_keys(name)#清除填充框后填-型号描述ele = smpUI.wd.find_element(By.ID, 'device-model-desc')ele.clear()ele.send_keys(desc)#点提交smpUI.wd.find_element(By.CSS_SELECTOR, '.add-one-submit-btn-div .btn').click()# time.sleep(1)#得到第一页的设备信息(注:一页五条),是显示第一页的第一个数据def get_first_page_device_models(self):time.sleep(1)self.wd.implicitly_wait(0)values = self.wd.find_elements(By.CSS_SELECTOR,'.field-value')self.wd.implicitly_wait(10)deviceModels = []for idx, value in enumerate(values):if (idx+1) % 3 == 0:deviceModels.append([values[idx-2].text, values[idx-1].text, values[idx].text])return deviceModels#删除第一个项目def del_first_item(self) -> bool:self.wd.implicitly_wait(0)delBtn = self.wd.find_elements(By.CSS_SELECTOR,'.result-list-item:first-child .result-list-item-btn-bar span:first-child')self.wd.implicitly_wait(10)if not delBtn:return FalsedelBtn[0].click()self.wd.switch_to.alert.accept()return True

3.2自动化测试脚本代码-商品服务

之间登录商品增删改查的界面。注意编完数据后要删除

python">from selenium.webdriver.common.by import By
import time,pytest
from lib.webUI_smp import smpUI
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from lib.cfg import *@pytest.fixture(scope='module')
def inDeviceModelMgr():print('inDeviceModelMgr setup')smpUI.login('byhy','sdfsdf' ) #直接登录smpUI.wd.get(SMP_URL_DEVICE_MODEL)#登录后转到SMP_URL_DEVICE_MODEL这个主界面yield@pytest.fixture()
def delAddedDeviceModel():yieldprint('删除添加的设备型号')smpUI.del_first_item()@pytest.mark.parametrize('type, device, desc', [("存储柜", 'hebut-cn-box-01', '河北工业大学菜鸟柜子01柜-10大20中40小'),#添加设备-存储柜测试("存储柜", '河'*100, '河北工业大学菜鸟柜子02柜-10大20中40小'),#测试名称最大长度
("电瓶车充电站", 'hebut-dpccdz-es-01', '河北工业大学北辰充电站01站-220v电瓶车充电站'),#添加设备-电瓶车充电站
("洗车站", 'hebut-xcz-washcar-01', '河北工业大学洗车站东站'),#添加设备-洗车站测试
("汽车充电站", 'hebut-powercar-01', '河北工业大学7千瓦汽车充电站01'),#添加设备-汽车充电站])
#添加设备-存储柜测试
def test_SMP_device_model_001(type,device,desc,inDeviceModelMgr, delAddedDeviceModel):# 点击添加按钮topBtn = smpUI.wd.find_element(By.CSS_SELECTOR, '.add-one-area > span')if topBtn.text == '添加':topBtn.click()smpUI.add_device_model(type,device,desc)dms = smpUI.get_first_page_device_models()assert  dms == [[type,device,desc    ]]smpUI.wd.implicitly_wait(3)def test_SMP_device_model_501(inDeviceModelMgr, delAddedDeviceModel):# 点击添加按钮topBtn = smpUI.wd.find_element(By.CSS_SELECTOR, '.add-one-area > span')if topBtn.text == '添加':topBtn.click()smpUI.add_device_model("存储柜", 'daixiugai-01', '待修改测试数据-01')smpUI.wd.implicitly_wait(3)# 点击修改按钮changeBtn = smpUI.wd.find_element(By.XPATH,'/html/body/main/div[3]/div/div[2]/span[2]').click()# if changeBtn.text == '修改':#     changeBtn.click()# 实例化选择框做为对象select = Select(smpUI.wd.find_element(By.XPATH,'/html/body/main/div[3]/div/div[1]/div[1]/select'))# 选择对应列表中的种类select.select_by_visible_text("洗车站")# 清除填充框后填-设备型号ele = smpUI.wd.find_element(By.XPATH,'/html/body/main/div[3]/div/div[1]/div[2]/input')ele.clear()ele.send_keys('修改后的型号1')# 清除填充框后填-型号描述ele = smpUI.wd.find_element(By.XPATH,'/html/body/main/div[3]/div/div[1]/div[3]/input')ele.clear()ele.send_keys('修改后的型号描述')# 点提交smpUI.wd.find_element(By.XPATH,'/html/body/main/div[3]/div/div[2]/span[1]').click()dms = smpUI.get_first_page_device_models()assert  dms == [["洗车站",'修改后的型号1','修改后的型号描述' ]]smpUI.wd.implicitly_wait(3)def test_SMP_device_model_601(inDeviceModelMgr, delAddedDeviceModel):# 点击添加按钮topBtn = smpUI.wd.find_element(By.CSS_SELECTOR, '.add-one-area > span')if topBtn.text == '添加':topBtn.click()smpUI.add_device_model("存储柜", 'daixshanchu-01', '待删除测试数据-01')time.sleep(1)smpUI.del_first_item()dms = smpUI.get_first_page_device_models()assert ['存储柜', 'daixshanchu-01', '待删除测试数据-01'] not in dmssmpUI.wd.implicitly_wait(3)

四、业务规则部分

4.1 lib.py-业务规则模块的封装

python">    def add_svc_rule(self, ruleName:str, ruleType:str,minFee:str,estFee:str, feeRate=None, desc:str=None):"""添加业务规则:param ruleName: 规则名称:param ruleType: 规则类型,只能是:后付费-上报业务量、预付费-下发费用、预付费-下发业务量:param minFee: 最小费用,不需要时,填写空字符串:param estFee: 预计费用,不需要时,填写空字符串:param desc: 描述:param feeRate: 费率, 如果ruleType是预付费-下发费用: 不用填写预付费-下发业务量: 格式为 ['千瓦时', '1'], 元素分别是 单位、单价后付费-上报业务量: 格式为 [['10L', '小时','1'],['20L', '小时','2'],], 每个元素里面分别是 : 业务码、单位、单价:return:"""#名称输入ele = self.wd.find_element(By.CSS_SELECTOR, '.add-one-form > .field:nth-child(1) >input')ele.clear()ele.send_keys(ruleName)select = Select(self.wd.find_element(By.CSS_SELECTOR, ".add-one-form select"))select.select_by_visible_text(ruleType)if ruleType != '后付费-上报业务量': #预付费-下发业务量操作ele = self.wd.find_element(By.CSS_SELECTOR, '.add-one-form > .field:nth-child(3) >input')ele.clear()if minFee:ele.send_keys(minFee)#输入最小消费ele =  self.wd.find_element(By.CSS_SELECTOR, '.add-one-form > .field:nth-child(4) >input')ele.clear()if estFee:ele.send_keys(estFee)#输入预估消费# 三者都有描述, 用xpath而不用 .field:nth-child 因为后付费-上报业务量 次序会变if desc:ele =  self.wd.find_element(By.XPATH,"//*[@class='add-one-submit-btn-div']/preceding-sibling::*[1]/input")ele.clear()ele.send_keys(desc)#输入对应描述# 费率填写if ruleType == '预付费-下发费用':# 没有费率设置passelif ruleType == '后付费-上报业务量':# 先删除上次添加遗留的费率self.wd.implicitly_wait(3)  # 先修改短等待时间while True:eles = self.wd.find_elements(By.CSS_SELECTOR, '.fee-rate span:last-child')if eles:eles[0].click() #删除之前的费率time.sleep(0.5)else:breakself.wd.implicitly_wait(3)  # 再改回来for one in feeRate:#遍历每个费率块self.wd.find_element(By.CSS_SELECTOR,'.fee-rate-list button').click()#锚定整个框entry = self.wd.find_element(By.CSS_SELECTOR,'div.fee-rate:nth-last-child(2)')# 输入业务码entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(1)').send_keys(one[0])# 输入计费单位entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(2)').send_keys(one[1])# 输入单位价格entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(3)').send_keys(one[2])elif ruleType == '预付费-下发业务量':#锚定整个框entry = self.wd.find_element(By.CSS_SELECTOR, 'div.fee-rate')# 输入计费单位entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(1)').send_keys(feeRate[0])# 输入单位价格entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(2)').send_keys(feeRate[1])else:raise Exception('ruleType 参数值错误')# 确定提交self.wd.find_element(By.CSS_SELECTOR, '.add-one-submit-btn-div .btn').click()self.wd.implicitly_wait(3)#业务部分查询首页def get_first_page_svc_rules(self):time.sleep(1)self.wd.implicitly_wait(0)items = self.wd.find_elements(By.CSS_SELECTOR,'.result-list-item-info')self.wd.implicitly_wait(10)rules = []for item in items:nameValueList = item.find_elements(By.CSS_SELECTOR, '.field>.field-name, .field>.field-value')itemInfo = []for idx, _ in enumerate(nameValueList):if (idx+1) % 2 == 0:nameEle,valueEle = nameValueList[idx-1], nameValueList[idx]if nameEle.text == '规则内容':ruleContent = {}sfns = valueEle.find_elements(By.CSS_SELECTOR,'.sub-field-name')for sfnEle in sfns:sfn = sfnEle.textsfvEle = sfnEle.find_element(By.XPATH, "following-sibling::*[1]")if sfn == '费率':ruleContent[sfn] = sfvEle.textelse:ruleContent[sfn] = sfvEle.textitemInfo.append(ruleContent)else:itemInfo.append(valueEle.text)rules.append(itemInfo)return rules#删除第一个项目def del_first_item(self) -> bool:self.wd.implicitly_wait(0)delBtn = self.wd.find_elements(By.CSS_SELECTOR,'.result-list-item:first-child .result-list-item-btn-bar span:first-child')self.wd.implicitly_wait(10)if not delBtn:return FalsedelBtn[0].click()self.wd.switch_to.alert.accept()return True

4.2自动化测试脚本代码-业务规则

注意事项跟3.2的商品的自动化测试脚本类似

python">from selenium.webdriver.common.by import By
import time,pytest
from lib.webUI_smp import smpUI
from lib.cfg import *@pytest.fixture(scope='module')
def inServiceRuleMgr():print('** inServiceRuleMgr setup **')smpUI.login('byhy','sdfsdf' )smpUI.wd.get(SMP_URL_SERVICE_RULE)yield@pytest.fixture()
def delAddedServiceRule():yieldprint('** 删除添加的业务规则')smpUI.del_first_item()@pytest.mark.parametrize('svcname, svctype,paymin,pay, svcdesc,jifeidanwei,feilv', [("全国-电瓶车充电费率1", "预付费-下发业务量", "0.1","2","全国-电瓶车充电费率1的描述",['千瓦时', '1'],None),#添加预付费-下发业务量])
def test_SMP_service_rule_001(svcname, svctype,paymin,pay, svcdesc,jifeidanwei,feilv,inServiceRuleMgr, delAddedServiceRule):# 点击添加按钮topBtn = smpUI.wd.find_element(By.CSS_SELECTOR,'.add-one-area > span')if topBtn.text == '添加':topBtn.click()smpUI.add_svc_rule(svcname, svctype,paymin,pay, jifeidanwei,svcdesc)dms = smpUI.get_first_page_svc_rules()assert dms[0][:3] == [svcname, svctype, {'最小消费': paymin, '预估消费': pay, '费率': f'单位:{jifeidanwei[0]} \n单价:{jifeidanwei[1]}'}]@pytest.mark.parametrize('svcname, svctype,paymin,pay, svcdesc,jifeidanwei,feilv', [("南京-洗车机费率1", "预付费-下发费用", "2","10","南京-洗车机费率1的描述",None,None),#预付费-下发费用])
def test_SMP_service_rule_101(svcname, svctype,paymin,pay, svcdesc,jifeidanwei,feilv,inServiceRuleMgr, delAddedServiceRule):# 点击添加按钮topBtn = smpUI.wd.find_element(By.CSS_SELECTOR,'.add-one-area > span')if topBtn.text == '添加':topBtn.click()smpUI.add_svc_rule(svcname, svctype,paymin,pay,svcdesc)dms = smpUI.get_first_page_svc_rules()assert dms[0][:3] == [svcname, svctype, {'最小消费': paymin, '预估消费': pay}]@pytest.mark.parametrize('svcname, svctype,paymin,pay, svcdesc,jifeidanwei,feilv', [("南京-存储柜费率1", "预付费-下发业务量", None,None,None,None,[['100L','小时','2']]),#添加预付费-下发业务量,['50L','小时','1'],['10L','小时','0.5']])
def test_SMP_service_rule_201(svcname, svctype,paymin,pay, svcdesc,jifeidanwei,feilv,inServiceRuleMgr, delAddedServiceRule):# 点击添加按钮topBtn = smpUI.wd.find_element(By.CSS_SELECTOR,'.add-one-area > span')if topBtn.text == '添加':topBtn.click()smpUI.add_svc_rule(svcname, svctype, paymin, pay,  svcdesc, feilv)dms = smpUI.get_first_page_svc_rules()assert dms[0][:3] == [svcname, svctype, {'业务码': f'单位:{feilv[0]} \n计费单位:{feilv[1]} \n单位价格:{feilv[2]}'}]

还有部分没粘上去,万变不离其宗,还要接口自动化测试,这里先不写,下次再写。 


http://www.ppmy.cn/ops/126266.html

相关文章

Centos7系统Python3.11.2版本安装

开发依赖包需要依赖于python3.11环境,但是目前python环境为3.6,于是需要修改python环境为3.11版本 Python 3.11 在 CentOS 7 中没有。我们将从源代码安装它 安装依赖包 yum -y update systemctl reboot yum -y install epel-release yum install wget…

SQL INNER JOIN:深入解析与实际应用

SQL INNER JOIN:深入解析与实际应用 引言 在关系型数据库管理系统中,SQL(Structured Query Language)是一种用于管理和操作数据库的标准编程语言。SQL INNER JOIN 是一种常用的查询技术,用于结合两个或多个数据库表中的相关行。本文将深入探讨 SQL INNER JOIN 的概念、语…

公寓智能水电系统

什么是公寓智能水电系统?简单来说,公寓智能水电系统是一种利用物联网技术,将家中的水电设备连接起来,实现远程监控与自动控制的解决方案。它包括但不限于智能电表、智能水表、漏电保护器、漏水检测器等硬件设施,以及配套的软件平…

根据Vue对比来深入学习React 下 props 组件传值 插槽 样式操作 hooks 高阶组件 性能优化

文章目录 函数组件的特点props组件间的传值父传子看上例子传父兄弟组件传值祖先组件传值 插槽基础插槽具名插槽作用域插槽 样式操作**CSS Modules** 生命周期useRef常用hookuseStateuseEffectuseContextuseReduceruseMemouseCallback 高阶组件什么时候使用 react性能问题和优化…

iOS 18升级:避免常见陷阱,顺利完成升级

随着iOS 18的发布,许多用户都希望尽快体验到新系统带来的新功能和改进。然而,升级过程可能会因为准备工作不足或对步骤的不熟悉而变得复杂。本文旨在为用户提供一个清晰的升级指南,确保升级过程既平滑又安全。 升级前的准备工作 在开始升级之…

力扣(leetcode)每日一题 3158 求出出现两次数字的 XOR 值 |位运算

3158. 求出出现两次数字的 XOR 值 题干 给你一个数组 nums ,数组中的数字 要么 出现一次,要么 出现两次。 请你返回数组中所有出现两次数字的按位 XOR 值,如果没有数字出现过两次,返回 0 。 示例 1: **输入&#…

网络安全(黑客技术)2024年100天学习计划

🤟 基于入门网络安全/黑客打造的:👉黑客&网络安全入门&进阶学习资源包 前言 什么是网络安全 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、…

查询数据库绘制历史曲线

<?php include ("jpgraph/jpgraph.php"); include ("jpgraph/jpgraph_line.php"); // // 假定数据库用户名&#xff1a;root&#xff0c;密码&#xff1a;123456&#xff0c;数据库&#xff1a;RUNOOB $conmysqli_connect("localhost",&qu…