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

【UI自动化测试】6_PO模式 _数据驱动

文章目录

  • 一、数据驱动
    • 1.1 数据驱动概念
    • 1.2 数据驱动实现步骤
  • 二、代码实现
    • 2.1 page
      • 2.1.1 login_page.py
    • 2.2 base
      • 2.2.1 base_page.py
    • 2.3 data
      • 2.3.1 tp_login_data.json
    • 2.4 utils.py
    • 2.5 script
      • 2.5.1 test_login.py

一、数据驱动

1.1 数据驱动概念

  • 什么是数据驱动?
以测试数据驱动用例执行(测试数据和代码分离)
  • 为什么要数据驱动?
便于维护(维护的焦点从代码转到测试数据)
  • 数据驱动实现步骤
前提:一条测试用例已经编写完毕(PO模式)。 - 1、提取测试数据并存储 - 2、编写读取数据的函数 - 3、测试用例追加参数化技术,获取数据实现数据驱动

1.2 数据驱动实现步骤

前提:一条测试用例已经编写完毕(PO模式)。 - 1、提取测试数据并存储 - 2、编写读取数据的函数 - 3、测试用例追加参数化技术,获取数据实现数据驱动

1、提取测试数据

[("13611111111","123456","8888","账号不存在!"),("13600001111","error","8888","密码错误")][["13611111111","123456","8888","账号不存在!"],["13600001111","error","8888","密码错误"]]口诀:1、新建json文件,在文件中编写一个{}2、有几个测试案例,写几个key(用例名称),value为字典3、每个{}中组成->说明+参数数据+预期结果{"account_not_exist":{"username":"13611111111","password":"123456","code":"8888","expect":"账号不存在!"},"password_error":{"username":"13600001111","password":"error","code":"8888","expect":"密码错误"}}

2、编写读取数据的函数

# 读取测试数据并返回成pytest参数化所要求的数据格式# [["13611111111", "123456", "8888","账号不存在!"],["13600001111", "error", "8888","密码错误"]]defbuild_data(file_name):# 完整的测试数据文件名file_path=os.path.dirname(__file__)+f"/data/{file_name}.json"# 定义空列表存储键值的数据列表case_data=[]# 1、读取json文件的所有数据withopen(file_path,encoding="utf-8")asf:all_data=json.load(f)# 2、遍历第一层的键值foriinall_data.values():# 3、获取该遍历的值的所有键值,并且强制转换为列表 # 4、需要保存读取到的测试数据# list(i.values()) ["13611111111", "123456", "8888","账号不存在!"]case_data.append(list(i.values()))# 5、返回测试数据returncase_dataprint(build_data("tp_login_data"))

3、测试用例追加参数化技术,获取数据实现数据驱动

  1. 在 通用测试方法上一行,添加 @pytest.mark.parameterize()
  2. 给 parameterize()添加参数。参1:一个字符串,内容为json文件中,一组测试数据的键。参2:[(), (), ()]格式数据 或者[[], [], []] 。
  3. 给 通用测试方法,添加形参。参数与 parameterize()的 参1 保持一致。
  4. 修改 通用测试方法 内部实现,使用 形参。

二、代码实现

version_06 (包) ①page - __init__.py - login_page.py ②base - __init__.py - base_page.py ③data - tp_login_data.json ④utils.py ⑤script - __init__.py - test_login.py (注:只测试登录参数化了)

2.1 page

2.1.1 login_page.py

fromselenium.webdriver.common.byimportByfromversion_06.utilsimportDriverUtilsfromversion_06.base.base_pageimportBasePage# 定义页面对象# 调用另一个类里面的实例方法:创建对象 或者 继承的方式classLoginPage(BasePage):# 定义页面实例属性:页面上的元素信息 -->存储对应元素的定位信息(定位方式、该定位方式所需要对应的值)def__init__(self):# 驱动对象self.driver=DriverUtils.get_driver()# 用户名输入框self.username=(By.ID,"username")# 密码输入框self.password=(By.ID,"password")# 验证码输入框self.verify_code=(By.ID,"verify_code")# 登录按钮self.login_btn=(By.XPATH,"//*[@class='login_bnt']/a")# 定义哪些元素:测试工程师所要测试的内容用到该页面哪些元素就定义哪些元素# 定义页面业务方法:组装该页面上的一些操作形成操作步骤deftp_login(self,user,pwd,code):""" :param user: 用户名 :param pwd: 密码 :param code: 验证码 :return: """# 输入用户名self.input_text(self.find_el(self.username),user)# 输入密码self.input_text(self.find_el(self.password),pwd)# 输入验证码self.input_text(self.find_el(self.verify_code),code)# 点击登录self.find_el(self.login_btn).click()""" # ①清空用户名输入框(为了加强测试代码的健壮性) self.find_el(self.username).clear() # 输入用户名 self.find_el(self.username).send_keys(user) # ②清空密码输入框(为了加强测试代码的健壮性) self.find_el(self.password).clear() # 输入密码 self.find_el(self.password).send_keys(pwd) # ③清空验证码输入框(为了加强测试代码的健壮性) self.find_el(self.verify_code).clear() # 输入验证码 self.find_el(self.verify_code).send_keys(code) # 点击登录 self.find_el(self.login_btn).click() """""" # 方法2:元祖拆包 # ①清空用户名输入框(为了加强测试代码的健壮性) self.driver.find_element(*self.username).clear() # 输入用户名 self.driver.find_element(*self.username).send_keys(user) # 清空密码输入框 self.driver.find_element(*self.password).clear() # 输入密码 self.driver.find_element(*self.password).send_keys(pwd) # 清空验证码输入框 self.driver.find_element(*self.verify_code).clear() # 输入验证码 self.driver.find_element(*self.verify_code).send_keys(code) # 点击登录 self.driver.find_element(*self.login_btn).click() """"""原始方法 # 输入用户名 self.driver.find_element(By.XPATH,"//*[@id='username']").send_keys(user) # 输入密码 self.driver.find_element(By.XPATH,"//*[contains(@id,'pass')]").send_keys(pwd) # 输入验证码 self.driver.find_element(By.XPATH,'//*[@placeholder="验证码" and @id="verify_code"]').send_keys(code) # 点击登录 self.driver.find_element(By.XPATH,"//*[@class='login_bnt']/a").click() """"""方法1 # 输入用户名 self.driver.find_element(self.username[0], self.username[1]).send_keys(user) # 输入密码 self.driver.find_element(self.password[0], self.password[1]).send_keys(pwd) # 输入验证码 self.driver.find_element(self.verify_code[0], self.verify_code[1]).send_keys(code) # 点击登录 self.driver.find_element(self.login_btn[0], self.login_btn[1]).click() """

2.2 base

2.2.1 base_page.py

importloggingfromselenium.webdriver.support.waitimportWebDriverWaitfromversion_06.utilsimportDriverUtils# 基类:存放二次封装代码classBasePage:def__init__(self):self.driver=DriverUtils.get_driver()# 公用元素定位deffind_el(self,location):try:# 显示等待el=WebDriverWait(self.driver,10,1).until(lambdax:x.find_element(*location))logging.info(f"成功找到元素:{location}")exceptExceptionase:el=Nonelogging.error(f"未找到元素:{location}")returnel# 公用模拟输入definput_text(self,element,text):try:# 清空输入框element.clear()# 输入文本element.send_keys(text)logging.info(f"输入文本成功:{text}")exceptExceptionase:logging.error(f"输入文本失败:{text}")# frame 切换defswitch_frame(self,i_el):try:# 切换到frameself.driver.switch_to.frame(i_el)logging.info(f"成功切换到frame:{i_el}")exceptExceptionase:logging.error(f"切换frame失败:{i_el}")# 窗口切换defswitch_window(self,n):try:# 1、获取所有窗口句柄handles=self.driver.window_handles# 2、切换到指定窗口self.driver.switch_to.window(handles[n])logging.info(f"成功切换到窗口:{n}")exceptExceptionase:logging.error(f"切换窗口失败:{n}")

2.3 data

2.3.1 tp_login_data.json

{"account_not_exist":{"username":"13611111111","password":"123456","code":"8888","expect":"账号不存在!"},"password_error":{"username":"13600001111","password":"error","code":"8888","expect":"密码错误"}}

2.4 utils.py

importjsonimportloggingimportos.pathfromtimeimportsleepfromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromselenium.webdriver.support.waitimportWebDriverWait# 驱动工具类classDriverUtils:# 初始化私有属性(不希望外部修改值)__driver=None# 获取浏览器驱动对象# 整个测试用例运行过程中会多次调用获取驱动对象的方法,按照实例方法调用的话每次都要创建对象,调用就会出现多个浏览器# 整个测试用例运行时,第一次打开浏览器驱动对象,则把浏览器驱动对象存储起来# 下次调用获取驱动对象时,判断当前是否有存储的浏览器驱动对象,如有则直接返回,如没有则创建@classmethoddefget_driver(cls):""" 1、拷贝一份共性的代码 2、修改代码的错误 3、分析封装的代码中是否要参数化数据 4、分析封装代码的运行结果是否需要返回 5、优化代码 :return:驱动对象 """ifcls.__driverisNone:cls.__driver=webdriver.Chrome()cls.__driver.maximize_window()cls.__driver.implicitly_wait(10)# 返回创建的浏览器驱动对象returncls.__driver# 关闭驱动对象@classmethoddefquit_driver(cls):# 为了加强代码的健壮性,避免单独调用关闭浏览器驱动方法时报错,在调用关闭驱动对象的方法时,判断当前是否有打开的浏览器# 关闭浏览器ifcls.__driverisnotNone:sleep(2)cls.__driver.quit()# 将__driver值恢复为Nonecls.__driver=None# 函数:公用的获取任意元素文本defget_el_text(xpath_str):# 获取元素文本# msg = DriverUtils.get_driver().find_element(By.XPATH, xpath_str).text# 重要的信息,最好是显示等待try:msg=WebDriverWait(DriverUtils.get_driver(),10,1).until(lambdax:x.find_element(By.XPATH,xpath_str)).textprint(msg)exceptExceptionase:logging.error("没有获取到{xpath_str}的元素对象文本!")msg=None# 返回获取的文本returnmsg# 函数:根据文本判断当前页面是否有对应的元素对象defel_is_exist_by_text(key_text):# 根据本次新增的【收货人】信息的文本,到界面上找元素,如果能找到则代表信息成功,找不到则失败截图try:# 显示等待# 如果找到元素对象则把元素对象赋值给is_suc变量is_suc=WebDriverWait(DriverUtils.get_driver(),10,1).until(lambdax:x.find_element(By.XPATH,f"//*[text()='{key_text}']"))exceptExceptionase:# 找不到则给is_suc变量赋值为Falseis_suc=False# 截图DriverUtils.get_driver().get_screenshot_as_file(f"{key_text}未找到.png")logging.error(f"未找到文本为{key_text}的元素对象!")# 返回是否找到结果returnis_suc# 读取测试数据并返回成pytest参数化所要求的数据格式# [["13611111111", "123456", "8888","账号不存在!"],["13600001111", "error", "8888","密码错误"]]defbuild_data(file_name):# 完整的测试数据文件名file_path=os.path.dirname(__file__)+f"/data/{file_name}.json"# 定义空列表存储键值的数据列表case_data=[]# 1、读取json文件的所有数据withopen(file_path,encoding="utf-8")asf:all_data=json.load(f)# 2、遍历第一层的键值foriinall_data.values():# 3、获取该遍历的值的所有键值,并且强制转换为列表 # 4、需要保存读取到的测试数据# list(i.values()) ["13611111111", "123456", "8888","账号不存在!"]case_data.append(list(i.values()))# 5、返回测试数据returncase_dataprint(build_data("tp_login_data"))

2.5 script

2.5.1 test_login.py

# 导包importpytestfromtimeimportsleepfromseleniumimportwebdriverfromselenium.webdriverimportActionChainsfromselenium.webdriver.common.byimportByfromversion_06.utilsimportDriverUtils,get_el_text,build_datafromversion_06.page.login_pageimportLoginPage# 1、定义测试类 --->模块(登录模块)classTestLogin():# 开始执行测试之前只会打开一次浏览器defsetup_class(self):# 类方法的调用:创建对象.方法()self.driver=DriverUtils.get_driver()# 所有的测试用例都运行完毕才会关闭浏览器defteardown_class(self):DriverUtils.quit_driver()# 每个测试方法的起点一致;那么证明每个测试方法运行之前都会回到首页defsetup(self):self.driver.get("https://hmshop-test.itheima.net/")# 2、定义测试方法 ---> 标题@pytest.mark.parametrize("username,password,verify_code,expect",build_data("tp_login_data"))deftest_login_success(self,username,password,verify_code,expect):# 4、暂停3s ->代替测试步骤# a。使用Xpath 文本定位策略定位登录超链接,并点击self.driver.find_element_by_xpath("//*[text()='登录']").click()# 通过调用LoginPage登录页面的登录方法完成登录操作LoginPage().tp_login(username,password,verify_code)# 获取实际结果,调用工具类中 get_el_text来获取文本信息msg=get_el_text("//*[@class='layui-layer-content layui-layer-padding']")# 断言:assert 表示期望结果为真assertexpectinmsg
http://www.jsqmd.com/news/412443/

相关文章:

  • Grafana 接入 SSO 配置指南
  • 华为晟腾计算芯片 —— AI国产化 —— Ascend / pytorch —— 支持NPU的pytorch下载地址
  • ArgoCD 接入 SSO 配置指南
  • 【每日一题】LeetCode 1356. 根据数字二进制下 1 的数目排序
  • HTML 布局
  • 信用卡债务协商最佳解决方案,信用卡债务协商真的能帮我摆脱困境吗? - 代码非世界
  • 文件夹监控文件变动通知器
  • 【eclipse 升级】
  • 像素蛋糕专用
  • 信用卡逾期后,如何才能成功申请60期分期?这样协商还款,压力瞬间减半 - 代码非世界
  • 大气电场监测仪:实时测量大气中的电场强度变化
  • 信用卡债务协商:探寻最佳解决方案,信用卡债务协商的最佳解决方案到底是什么? - 代码非世界
  • 11.3 监控与可观测性:指标体系、日志追踪、drift检测
  • LuxTTS语音克隆
  • 青木川古镇酒店排名哪家好?2026最新榜单,青云客栈稳居首选! - 一个呆呆
  • 11.2 模型路由与网关:多模型调度、流量切分、故障转移
  • 青木川酒店排名哪家好?2026最新榜单,青云客栈稳居首选! - 一个呆呆
  • 11.1 AI工程五步构建法:增强上下文、护栏、路由、缓存、智能体
  • 小白也能轻松做GEO优化了,立省万元
  • 每天登录10个自媒体后台太累了试试这个一键发布工具
  • 10.3 服务优化:连续批处理、动态批处理、负载均衡实战
  • 10.4 AI加速器选型:GPU、TPU、NPU架构与算力对比
  • 软件专业毕设中HTML技术与Python技术如何结合用
  • LeetCode 1356.根据数字二进制下 1 的数目排序:自定义排序模拟
  • django基于python文化旅游信息公开管理平台的设计与实现
  • 信用卡与贷款协商分期 委托律师处理的全流程实操指南,信用卡和贷款协商分期,到底该怎么委托律师处理? - 代码非世界
  • 最高补 1000 万!2026 福建省级 AI 项目申报全攻略,AI企业必看的申报要点与实操指南
  • 律师协助下信用卡与贷款分期协商全攻略,委托律师处理信用卡分期协商到底有多靠谱? - 代码非世界
  • AI原生应用:重塑视频生成格局
  • 信用卡逾期找律师协商分期还款靠谱吗?选择和律掌柜,选择专业、可靠、有效的债务解决方案 - 代码非世界