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

Python —— UI自动化之Page Object模式

1、Page Object模式简介

1、二层模型

        Page Object Model(页面对象模型), 或者也可称之为POM。在UI自动化测试广泛使用的一种分层设计 模式。核心是通过页面层封装所有的页面元素及操作,测试用例层通过调用页面层操作组装业务逻辑。

1、实战 

目录如下:

home_page.py文件的内容:

from selenium.webdriver.common.by import Byclass HomePage:login_link_locator = (By.LINK_TEXT, '登录')def click_login_link(self,driver):# 前面加*号是解包的操作,因为login_link_locator是元组driver.find_element(*self.login_link_locator).click()

login_page.py文件的内容:

from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import Byclass LoginPage:#属性->元素定位信息(元素定位方法+元素定位值)-元组类型phone_input_locator = (By.XPATH,'//input[@placeholder="请输入手机号/用户名"]')pwd_input_locator = (By.XPATH,'//input[@placeholder="请输入密码"]')login_button_locator = (By.CLASS_NAME,'login-button')#操作->元素行为,登录操作def page_login(self,driver,phone,pwd):# *self.phone_input_locator 前面的*号是解包使用的driver.find_element(*self.phone_input_locator).send_keys(phone)driver.find_element(*self.pwd_input_locator).send_keys(pwd)sleep(2)driver.find_element(*self.login_button_locator).click()

登录案例 - PO.py的文件内容:

from selenium import webdriver
from d6_JavaScript处理.testcases.home_page import HomePage
from d6_JavaScript处理.testcases.login_page import LoginPagedriver = webdriver.Chrome()
driver.maximize_window()
driver.get("http://mall.banan.com:3344/")
HomePage().click_login_link(driver)LoginPage().page_login(driver,"1723693766728","ydgcdlcb")

2、三层模型

        基本的PO分层包括页面层与用例层,但是在编写页面层代码时会发现一个问题:页面中存在非常多相同 的操作方法,比如都需要等待元素、获取元素属性/文本信息、页面滚动等等,每个页面层类都需要有相 同的代码,代码存在非常多冗余。我们可以把这些【公共】的页面操作方法给提取出来放到一个类中进 行维护,其他的页面类共用该类中的操作方法即可(通过继承实现)。

UI自动化断言:
        断言是自动化测试不可缺少的部分,当我们使用测试脚本对业务逻辑进行操作时,需要检查交互操作之 后结果的正确性,此时需要通过断言机制来进行验证。

        Pytest测试框架内置丰富的断言,通过assert语句即可,常见的断言方法比较包括:

  • 比较相等
assert a == b
  • 比较大小(大于/小于/大于等于/小于等于)
assert a > b
  • 内容包含/内容不包含
assert a in b
  • 验证表达式是否为真
assert condition
UI自动化常见的断言条件包括:
  • 通过当前页面的URL地址

  • 通过当前页面的标题
  • 通过当前页面的提示文本信息
  • 通过当前页面的某些元素变化/显示

一句话总结:通过肉眼观察页面的变化检查

3、三层模型实战

思路:抽取一个公共类,这个类中可以写公共页面的属性和函数,也可以写每次都要使用的属性,从UI自动化的角度来看,浏览器驱动是每次执行用例都会用到的,所以也可以抽取出来。

三层模型的文件目录如下:

base_page.py文件中的内容:

import osfrom selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait# BasePage 用来存放所有页面类的公共部分,一些公共的操作(显式封装)
class BasePage:def __init__(self,driver):self.driver = driver# 封装的意思:把相同类似的代码放到一个函数里面,重复使用# locator是元组的类型def wait_element_clickable(self, locator):web_element = WebDriverWait(self.driver,5,0.5).until(EC.element_to_be_clickable(locator))return web_elementdef wait_element_visible(self, locator):# web_element代表通过显示等待找到的元素web_element = WebDriverWait(self.driver,5,0.5).until(EC.visibility_of_element_located(locator))return web_elementdef wait_element_presence(self, locator):web_element = WebDriverWait(self.driver,5,0.5).until(EC.presence_of_all_elements_located(locator))return web_element# JavaScript进行元素的滚动def page_scroll(self,distance):self.driver.execute_script(f"document.documentElement.scrollTop={distance}")# JavaScript进行元素的点击def page_js_click(self,locator):element = self.wait_element_visible(self.driver,locator)self.driver.execute_script("arguments[0].click()",element)# JavaScript进行元素的移除def remove_element_attribute(self,locator,attribute):element = self.wait_element_visible(self.driver,locator)self.driver.execute_script(f"arguments[0].removeAttribute({attribute})", element)# 鼠标点击def mouse_click(self,locator):element = self.wait_element_visible(self.driver,locator)ActionChains(self.driver).click(element).perform()# 窗口切换def switch_to_window(self,title):handles = self.driver.window_handlesfor handle in handles:if self.driver.title == title:breakelse:self.driver.switch_to.window(handle)# 文件上传def update_file(self,filepath):os.system(f"test.exe {filepath}")

home_page.py文件中的内容:

import timefrom selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PO模式优化与自动化用例断言.common.base_page import BasePageclass HomePage(BasePage):# 属性-登录链接login_link_locator = (By.LINK_TEXT,'登录')# 欢迎提示信息welcome_tips_locator = (By.XPATH,'//span[text()="欢迎来到天使的世界"]')welcome_tips_text_locator = (By.XPATH,'//span[@class="text"]')# 用户名username_text_locator = (By.XPATH,'//a[@class="link-name"]')def click_login_link(self):self.wait_element_clickable(self.login_link_locator).click()def is_display_welcome_tips(self):time.sleep(2)# return  self.wait_element_clickable(self.welcome_tips_locator).is_displayed()return self.wait_element_clickable(self.welcome_tips_text_locator).textdef get_username_text(self):return self.wait_element_visible(self.username_text_locator).text

login_page.py文件中的内容: 

import timefrom selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PO模式优化与自动化用例断言.common.base_page import BasePageclass LoginPage(BasePage):# 属性->元素定位信息(元素定位方法+元素定位值)-元组类型phone_input_locator = (By.XPATH, '//input[@placeholder="请输入手机号/用户名"]')pwd_input_locator = (By.XPATH, '//input[@placeholder="请输入密码"]')login_button_locator = (By.CLASS_NAME, 'login-button')login_tips_locator = (By.XPATH, '//p[@class="el-message__content"]')def login(self,phone,pwd):# 因为继承了 basepage类,所以克不用再写driver参数# self.wait_element_visible(self.driver,self.phone_input_locator).send_keys("17728373518")self.wait_element_visible(self.phone_input_locator).send_keys(phone)self.wait_element_visible(self.pwd_input_locator).send_keys(pwd)self.wait_element_clickable(self.login_button_locator).click()time.sleep(3)def get_login_tips(self):# 这里比较文本内容return self.wait_element_visible(self.login_tips_locator).textprint(self.wait_element_visible(self.login_tips_locator).text)

test_login.py文件中的内容

from selenium import webdriver
from d7_PO模式优化与自动化用例断言.pageobjects.home_page import HomePage
from d7_PO模式优化与自动化用例断言.pageobjects.login_page import LoginPagedef test_login_success():driver = webdriver.Chrome()driver.get("http://mall.banan.com:3344/")driver.maximize_window()# 点击首页的登录操作homepage = HomePage(driver)homepage.click_login_link()# 在登陆页面进行登录操作loginpage = LoginPage(driver)loginpage.login("le_auto","le123456")# 断言检测测试是否成功(通过预期结果和实际结果的比较)#  检查点:1、欢迎页,如果函数的返回值为True,那么断言之后返回是通过的assert homepage.is_display_welcome_tips()# assert loginpage.get_login_tips() == '账号或者密码不正确'assert homepage.get_username_text() == 'lemon_auto'# 对登录结果的断言
def test_login_uncorrect_username():driver = webdriver.Chrome()driver.get("http://mall.banan.com:3344/")homepage = HomePage(driver)homepage.click_login_link()# 在登陆页面进行登录操作loginpage = LoginPage(driver)loginpage.login("le_auto1", "le123456")# 页面登录过程中的提示信息断言assert loginpage.get_login_tips() == '账号或密码不正确'

2、PO模式的优点

1、提高测试用例的可读性

2、提高测试用例可维护性

3、减少代码重复

相关文章:

Python —— UI自动化之Page Object模式

1、Page Object模式简介 1、二层模型 Page Object Model(页面对象模型), 或者也可称之为POM。在UI自动化测试广泛使用的一种分层设计 模式。核心是通过页面层封装所有的页面元素及操作,测试用例层通过调用页面层操作组装业务逻辑。 1、实战 …...

职能篇—自动驾驶产品经理

自动驾驶产品开发流程 在讲自动驾驶产品经理之前,先简单了解一下自动驾驶的开发体系。如上图所示,从产品需求开始,经由系统需求、系统架构、软件需求、软件架构,最终分解到软件代码实现模块,再经由MIL、SIL、HIL、VIL完…...

ubuntu安装golang

看版本:https://go.dev/dl/ 下载: wget https://go.dev/dl/go1.21.3.linux-amd64.tar.gz卸载已有的go,可以apt remove go,也可以which go之后删除那个go文件,然后: rm -rf /usr/local/go && tar…...

ES 8 新特性

1. async 和 await async 和 await 两种语法结合可以让异步代码像同步代码一样。(即:看起来是同步的,实质上是异步的。) 先从字面意思理解,async 意为异步,可以用于声明一个函数前,该函数是异步的。await 意为等待,即等待一个异步方法完成。 1.1 async async 声明(…...

linux-防火墙

目录 一、防火墙概念 1.软件防火墙 2.iptables默认规则 3.iptables的五链 4.iptables动作 5.四表五链 6.iptables实例 一、防火墙概念 linux下防火墙一般分为软件防火墙、硬件防火墙 硬件防火墙:在硬件的级别实现防火墙过滤功能,性能高&#xf…...

Pytorch--3.使用CNN和LSTM对数据进行预测

这个系列前面的文章我们学会了使用全连接层来做简单的回归任务,但是在现实情况里,我们不仅需要做回归,可能还需要做预测工作。同时,我们的数据可能在时空上有着联系,但是简单的全连接层并不能满足我们的需求&#xff0…...

爬虫进阶-反爬破解9(下游业务如何使用爬取到的数据+数据和文件的存储方式)

一、下游业务如何使用爬取到的数据 (一)常用数据存储方案 1.百万级别数据:单机数据库,搭建和使用方便快捷,成本低 2.千万级别数据:负载均衡的多台数据库,安全和稳定 3.海量数据:…...

Docker常用应用部署

Docker常用应用部署 一、Ubuntu系统Docker快速安装 Docker官网安装文档:https://docs.docker.com/engine/install/ubuntu/ # 文本处理的流编辑器 -i直接修改读取的文件内容,而不是输出到终端 # sed -i s/原字符串/新字符串/ /home/1.txt # 下面这个是修…...

【数据分享】2014-2022年我国淘宝村点位数据(Excel格式/Shp格式)

电子商务是过去一二十年我国发展最快的行业,其中又以淘宝为代表,淘宝的发展壮大带动了一大批服务淘宝电子商务的村庄,这些村庄被称为淘宝村! 截至到目前,阿里研究院梳理并公布了2014-2022年共9个年份的淘宝村名单&…...

Ubuntu 安装 docker-compose

在Ubuntu上安装Docker Compose,可以按照以下步骤进行操作: 下载 Docker Compose 二进制文件 sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker…...

vue2、vue3中路由守卫变化

什么是路由守卫? 路由守卫就是路由跳转的一些验证,比如登录鉴权(没有登录不能进入个人中心页)等等等 路由守卫分为三大类: 全局守卫:前置守卫:beforeEach 后置钩子:afterEach 单个…...

Leetcode—547.省份数量【中等】

2023每日刷题(八) Leetcode—547.省份数量 实现代码 static int father[210] {0};int Find(int x) {if(x ! father[x]) {father[x] Find(father[x]);}return father[x]; }void Union(int x, int y) {int a Find(x);int b Find(y);if(a ! b) {fathe…...

Nginx 防盗链

nginx防盗链问题 盗链: 就是a网站有一张照片,b网站引用了a网站的照片 。 防盗链: a网站通过设置禁止b网站引用a网站的照片。 nginx防止网站资源被盗用模块 ngx_http_referer_module 如何区分哪些是不正常的用户? HTTP Referer…...

26. 通过 cilium pwru了解网络包的来龙去脉

pwru是一种基于eBPF的工具,可跟踪Linux内核中的网络数据包,并具有先进的过滤功能。它允许对内核状态进行细粒度检查,以便通过调试网络连接问题来解决传统工具(如iptables TRACE或tcpdump)难以解决甚至无法解决的问题。在本文中,我将介绍pwru如何在不必事先了解所有内容的…...

刷题笔记day01-数组

704 题 主要强调,左闭右闭的情况,就是每次查询都会和 [left, right] 进行比较。所以后面的都是mid-1,mid1 的情况。 package mainfunc search(nums []int, target int) int {// 二分查找方法// 每次查找都是左闭右闭的情况left : 0right : …...

C#调用C++ 的DLL传送和接收中文字符串

1 c#向c传送中文字符串 设置&#xff1a;将 字符集 改为 使用多字节字符集 cpp代码&#xff1a; extern "C"_declspec(dllexport) int input_chn_str(char in_str[]) {cout<<in_str<<endl;return 0; }c#代码&#xff1a; [DllImport("Demo.dll…...

【MySQL】数据库常见错误及解决

目录 2003错误&#xff1a;连接错误1251错误&#xff1a;身份验证错误1045错误&#xff1a;拒绝访问错误服务没有报告任何错误net start mysql 发生系统错误 5。 1064错误&#xff1a;语法错误1054错误&#xff1a;列名不存在1442错误&#xff1a;触发器中不能对本表增删改1303…...

spring常见问题汇总

1. 什么是spring? Spring是一个轻量级Java开发框架&#xff0c;最早有Rod Johnson创建&#xff0c;目的是为了解决企业级应用开发的业务 逻辑层和其他各层的耦合问题。它是一个分层的JavaSE/JavaEE full-stack&#xff08;一站式&#xff09;轻量级开源框架&#xff0c; 为开…...

java8 Lambda表达式以及Stream 流

Lambda表达式 Lambda表达式规则 Lambda表达式可以看作是一段可以传递的代码&#xff0c; Lambda表达式只能用于函数式接口&#xff0c;而函数式接口只有一个抽象方法&#xff0c;所以可以省略方法名&#xff0c;参数类型等 Lambda格式&#xff1a;&#xff08;形参列表&…...

基于Java的音乐网站管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...