web自动化之PO模式

news2024/10/5 15:33:58

PO模式

1、为什么需要PO思想?

首先我们观察和思考一下,目前我们写的作业脚本的问题: 元素定位和操作动 作写到一起了,这就就会用导致一个问题:

  • UI的页面元素比较容易变化的,所以元素定位和脚本操作写到一起,一旦 元素发生了变化,这些脚本都需要修改
  • 特别是登录页面在很多个页面都会涉及到 被引用,那么就会导致: 维护成 本比较大。 所以,我们通过PO模式来解决这个问题。

2、什么是PO模式

Page Object Model(页面对象模型), 或者也可称之为POM。在UI自动化测试 广泛使用的一种分层设计模式。

page就是网页的页面层,object就是封装的LoginPage 类:每一个页面一个 类,包含业务逻辑和测试对象

  • 页面元素元素定位: 定义为类的属性
  • 页面的操作行为 : 定义为类的方法
  • 业务逻辑: 对页面的操作 为了得到实际结果的过程 和步骤 ,这是测试 对象

测试用例+ 测试数据层: 单独维护。 包含测试逻辑步骤和测试用例

  • 测试逻辑: 测试部分 ,预期结果和实际结果的对比 ,这是测试用例

PO核心是通过页面层封装所有的页面元素及操作,测试用例层通过调用页面层 操作组装业务逻辑。

PO模式的核心思想:体现了业务逻辑和测试逻辑 的分离,测试用例和测试对象分离

以登录操作为例:

  • 获取页面登录错误信息 登出 等操作都是业务逻辑,单独进行PageObject 的封装。
  • 用例里只传用例数据,不会出现元素定位的代码。包括断言里也不要出现 元素定位。

PO模式最终的实现效果:

页面层:

  • 页面类A(A1 A2 A3)
  • 页面类B(B1 B2 B3) 页面类C(C1 C2 C3)

用例层:

  • 用例1 = A1 + B2 + C3
  • 用例2 = A1 + B2 + C1

PO模式优点:

  • 提高测试用例的可读性
  • 提高测试用例可维护性
  • 减少代码重复

我们现在以登录页面为例:登录页面类

因为这个页面里有元素定位 + 元素操作: 把这些东西最好是封装在一起,方便 被用例层调用。

  • 页面里的元素: 写成类的属性
    • 用元组形式表示;因为后面显示等待都是用元组调用的;调用用self调 用 ;
    • 并不需要一次性把所有元素都写出来,可以后续扩展
  • 页面的操作: 封装成实例方法
    • driver先没有,
    • 可以作为参数 一些变化的数据也参数化

三层PO思想【BasePage封装思想】

但是这样写还有个问题:既然每个元素都用显示等待操作,每个页面都写一 遍太麻烦,冗余度太高了;而且每个页面都有一些其他的共同的操作,比如点 击,输入文本等;那么每个页面都重复写,是不是可以进一步优化呢?

  • 这些每个页面都会调用的方法【等待,点击,输入文本等】,就属于公共 方法; BasePage 封装思想
  • 用三层PO模式: 公共页面的内容单独提取出来封装:这也叫做 。封装成为一个BasePage类。
  • 其他页面自己独有的元素和方法依然放在单独页面类里封装;需要用到 basepage类的内容的时候,如何实现?--- 类的继承实现

所以新建一个common的目录,建一个base_page的py文件,方所有的功能 方法。

  • BasePage 用来存放所有页面类的公共部分,一些公共的操作(显式封装)
  • 封装一个BasePage的类,里面的方法都是每个页面都要用的公共的方法。

base_page.py
from time import sleep

import pyautogui
import pyperclip
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains

class BasePage:

    # driver每个方法都用,如果直接定位参数,没有办法实现实例方法共享,所以可以定义为实例属性 实现共享
    def __init__(self,driver): # 初始化方法里定义了以参数  到时候实例化对象传参
        """初始化函数 定义driver作为实例属性 实例实例方法共享这个实例属性"""
        self.driver = driver

    # 操作和行为 行为为实例方法
    def wait_element_clickable(self, locator):
        web_element = WebDriverWait(self.driver, 8, 0.5).until(EC.element_to_be_clickable(locator))
        return web_element

    def wait_element_visible(self, locator):
        web_element = WebDriverWait(self.driver, 8, 0.5).until(EC.visibility_of_element_located(locator))
        return web_element

    def wait_element_presence(self, locator):
        web_element = WebDriverWait(self.driver, 8, 0.5).until(EC.presence_of_element_located(locator))
        return web_element

    # 1、普通点击操作 --关键字
    def click_element(self,locator):
        self.wait_element_clickable(locator).click()

    # 2、鼠标点击操作
    def mouse_click(self,locator):
        # 先找到元素
        element = self.wait_element_visible(locator)
        # 用鼠标点击
        ActionChains(self.driver).click(element).perform()

    # 3、js点击操作
    def js_click(self,locator):
        # 先找到元素
        element = self.wait_element_visible(locator)
        # 用js传参点击
        self.driver.execute_script("arguments[0].click()",element)

    # 4、输入数据文本
    def input_text(self,locator,text):
        self.wait_element_visible(locator).send_keys(text)

    # 5、获取元素的文本 : 拿到这个文本 返回这个文本
    def get_text(self,locator):
        return self.wait_element_visible(locator).text

    # 6、获取元素的属性:拿到这个属性的值 设置为返回值
    def get_attribute(self,locator,attr_name):
        return self.wait_element_visible(locator).get_attribute(attr_name)

    # 7、窗口切换
    def switch_window(self,url):
        # 先拿到所有的窗口句柄
        handles = self.driver.window_handles
        for win in handles:
            if self.driver.current_url == url:  # 判断当前的页面是否为想要的url地址
                break
            else:
                self.driver.switch_to.window(win)  # 如果不是 继续切换

    # 8、移动鼠标
    def move_mouse(self,locator):
        element = self.wait_element_presence(locator)
        ActionChains(self.driver).move_to_element(element).perform()

    # 9、文件上传
    def file_upload(self,file_path):
        # 1、先复制路径
        pyperclip.copy(file_path)
        # 2、粘贴 -- hotkey 通过热键粘贴
        pyautogui.hotkey("ctrl", "v")
        pyautogui.press("enter", presses=2)
home_page_v1.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

class HomePage:
    # 页面元素元素定位: 定义为类的属性 --元组
    loc_login = (By.XPATH, '//a[text()="登录"]')

    # 操作和行为 行为为实例方法
    def wait_element_clickable(self,driver,locator):
        web_element = WebDriverWait(driver, 8, 0.5).until(EC.element_to_be_clickable(locator))
        return web_element

    def wait_element_visible(self,driver,locator):
        web_element = WebDriverWait(driver, 8, 0.5).until(EC.visibility_of_element_located(locator))
        return web_element

    def wait_element_presence(self,driver,locator):
        web_element = WebDriverWait(driver, 8, 0.5).until(EC.presence_of_element_located(locator))
        return web_element

    # 点击首页里的登录链接按钮 打开登录页面 操作-- 定义为实例方法
    def click_login_link(self,driver):
        self.wait_element_visible(driver,self.loc_login).click()
test_login.py
"""
编写测试用例 执行测试用例 断言 的框架 - pytest框架
"""
from page_object.login_page_v1 import LoginPage
from page_object.home_page_v1 import HomePage
from selenium import webdriver

# pytest框架编写测试用例
def test_login():
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get("http://mall.lemonban.com:3344/")
    # 1、点击homepage 登录的链接 == 先实例化对象,再调用实例方法,实例方法要传参driver
    HomePage().click_login_link(driver)
    # 2、调用LoginPage里的login实例方法  执行登录操作== 先实例化对象,再调用实例方法,实例方法要传参
    LoginPage().login(driver,"lemon_py","12345678")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1689397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Sync FIFO介绍及基于Verilog的实现】

Sync FIFO介绍及实现 1 Intro2 Achieve2.1 DFD2.2 Intf2.3 Module 本篇博客介绍无论是编码过程中经常用到的逻辑–FIFO;该FIFO是基于单时钟下的同步FIFO; FiFO分类:同步FiFO VS 异步FiFO; 1 Intro FIFO可以自己实现,但…

如何安全地进行隔离网数据导出,提升文件流转效率?

隔离网(也称为隔离区或DMZ,即Demilitarized Zone)是一种网络安全措施,用于将内部网络与外部网络(如互联网)隔离开来,以减少安全风险。隔离网数据导出通常需要采取一些特殊的安全措施来确保数据的…

pod介绍之 容器分类与重启策略

目录 一 pod 基础概念介绍 1,pod 是什么 2,Pod使用方式 3,如何解决一个pod 多容器通信 4,pod 组成 5, k8s 中的 pod 二 pause容器 1,pause容器 是什么 2,pause容器作用 3&#xff…

【嵌入式Linux】Cmake、makefile、Cmakelist

记录嵌入式 linux环境下的编译方式 测试之前确保你的 Ubuntu 机器上安装了Gcc和cmake 1. 编译有以下几种方式 在 Linux系统下,编译一个 .c文件可以有以下几种方式: 直接用 Gcc 编译器编译为可执行文件编写Makefile文件,使用 make 指令&…

[LEECODE每日一题]找出最具竞争力的子序列

好久没有更新CSDN了,这段时间学业压力比较忙所以没有时间写,今天有时间来看看LEECODE的每日一题,碰巧刷到了这样一道题; 题目给的很清楚,既输入一个序列要求给定一个子序列长度,让其输出为一个最有"竞争力"的序列,说白了就是在所有子序列比较中,处于靠前位置的元素要…

Kafka之【生产消息】

消息(Record) 在kafka中传递的数据我们称之为消息(message)或记录(record),所以Kafka发送数据前,需要将待发送的数据封装为指定的数据模型: 相关属性必须在构建数据模型时指定,其中…

第2天 搭建安全拓展_小迪网络安全笔记

1.常见搭建平台脚本使用: 例如 phpstudy IIS Nginx(俗称中间件): 什么是中间件: 中间件是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用&#…

论文阅读--ViLD

现在的目标检测数据集,标注的类别都很有限,如图中的base categories,只能检测出toy而不能检测出细分类别,能不能在现有数据集的基础上,不额外打标注,就能直接检测细分物体? (a&#…

订餐系统总结、

应用层: SpringBoot:快速构建Spring项目,采用“约定大于配置”的思想,简化Spring项目的配置开发。 SpringMvc:Spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合,可以无缝集成。 Sprin…

深度学习之Python+OpenCV+Tensorflow实时人体检测和计数

欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习之PythonOpenCVTensorflow实时人体检测和计数项目简介 一、项目背景与意义 随着科技的不断发展&#xff…

Spring 事件监听

参考:Spring事件监听流程分析【源码浅析】_private void processbean(final string beanname, fi-CSDN博客 一、简介 Spring早期通过实现ApplicationListener接口定义监听事件,Spring 4.2开始通过EventListener注解实现监听事件 FunctionalInterface p…

Excel插入多行VBA实现

我们还可以利用 VBA(Visual Basic for Applications)宏语言,在 Excel 中写一个 VBA 宏来自动插入多行数据。这种方法可以方便我们自定义需要插入的行数和插入位置。下面是编写 VBA 宏的步骤: 1、按下Alt F11快捷键,打…

python文件名通常以什么结尾

python文件后缀一般有两个,分别是.py和.pyw。视窗用 python.exe 运行 .py,用 pythonw.exe 运行 .pyw 。 这纯粹是因为安装视窗版Python时,扩展名 .py 自动被登记为用 python.exe 运行的文件,而 .pyw 则被登记为用 pythonw.exe 运…

c++ - vector容器常用接口模拟实现

文章目录 一、成员变量二、常用迭代器接口模拟实现三、一些常用接口模拟四、默认成员函数五、功能测试 一、成员变量 我们通过在堆上申请一个数组空间来进行储存数据,我们的成员变量是三个指针变量,分别指向第一个位置、最后储存有效位置的下一个位置以…

OpenMV学习笔记1——IDE安装与起步

目录 一、OpenMV IDE下载 二、OpenMV界面 三、Hello World! 四、将代码烧录到OpenMV实现脱机运行 五、插SD卡(为什么买的时候没送?) 一、OpenMV IDE下载 浏览器搜索OpenMV官网,进入后点击“立即下载”&#xff0…

org.json下载方法

介绍org.json下载的一些方法。 工具/原料 浏览器 方式一 在百度上搜索org.json,点击第一个搜索结果。进入JSON网站后,可以看到有各种语言版本的json工具包,选择JSON-java。 点击JSON-java后页面跳转到GitHub上,在该网页上点击…

吉林大学软件工程易错题

1.【单选题】软件工程方法是( )。 A、为开发软件提供技术上的解决方法 (软件工程方法 ) B、为支持软件开发、维护、管理而研制的计算机程序系统(软件工程工具) …

Linux基础(四):Linux系统文件类型与文件权限

各位看官,好久不见,在正式介绍Linux的基本命令之前,我们首先了解一下,关于文件的知识。 目录 一、文件类型 二、文件权限 2.1 文件访问者的分类 2.2 文件权限 2.2.1 文件的基本权限 2.2.2 文件权限值的表示方法 三、修改文…

爬虫实训案例:中国大学排名

近一个月左右的时间学习爬虫,在用所积累的知识爬取了《中国大学排名》这个网站,爬取的内容虽然只是可见的文本,但对于初学者来说是一个很好的练习。在爬取的过程中,通过请求数据、解析内容、提取文本、存储数据等几个重要的内容入…

MT3039 山脉

思路: 往右看能看到山顶,可以看成找第一个比当前元素>的元素,即构造单调递减栈。 例子: 7 5 3 4 1. 7入栈: 7 2. 5入栈: 7 5 ansans1(1是指有1个元素(7)可以看到5) 3. 3入栈: 7 5 3 ansans2(2是指…