(十) web自动化测试-PO设计模式

2023-11-10

(十) web自动化测试-PO设计模式



前言

PO设计模式

PO(page object)设计模式是在自动化测试中已经流行起来的一种易于维护和减少代码的设计模式. 在自动化测试中, PO对象作为一个与页面交互的接口. 测试中需要与页面的UI进行交互时, 便调用PO的方法. 这样做的好处是, 如果页面的UI发生了更改,那么测试用例本身不需要更改, 只需更改PO中的代码即可.

PO设计模式具有以下优点:

  • 测试代码与页面的定位代码(如定位器或者其他的映射)相分离.
  • 该页面提供的方法或元素在一个独立的类中, 而不是将这些方法或元素分散在整个测试中.

一、PageObject原则

  • 使用方法去代替页面的功能点
  • 不要过多暴露页面的细节
  • 封装PO本身不要有断言
  • 一个方法要返回另一个页面对象(涉及跳转时使用)
  • 不要为页面中的每一个功能都去进行封装,只封装重要的功能即可
  • 对于不同的结果,需要定义不同的方法

1. 使用方法代替页面的功能点

页面中通常有很多功能点,比如登录、注册、搜索等,在PO中定义方法来代替这些功能,在方法中定义功能的操作逻辑

2. case中不要过多暴露页面的细节

执行的case中,不要暴露操作的细节,通常是直接调用封装好的po中的方法,比如:

def test_login(self):
	self.index.gotologin()

通常细节封装在po定义的方法中,不在测试用例中暴露,这样方便后续的维护,页面有变动时,只需要修改po中方法即可,测试断言相关部分不用修改

3. po本身不进行断言

在po定义的方法中不要进行断言操作,尽力保持页面逻辑和测试逻辑的分离,方便后续的维护

4. 一个方法返回另一个页面(PO)

PO中定义个方法,如果跳转至另外一个页面,可以直接return至对应跳转的页面,不要在一个方法中写多个页面,不利于后续的维护,有跳转的页面时,直接把跳转的页面定义成一个PO即可,然后在跳转方法中进行rerurn即可

5. 只为页面中的重要元素创建page类

通常一个页面的功能是很多的,我们不能为每一个元素创建page类,只为重点关注的功能创建po即可,比如百度首页中,我们为首页、登录及搜索功能创建po即可

6. 对于不同的结果定义不同的方法

测试过程中,通常对于一个功能点,有正常的场景,还有异常的场景,在PO中可以定义不同的方法来实现不同结果,比如登录,我们可以定义多个方法进行测试

def login_success(self):
	pass

def login_passwd_wrong(self):
	pass

def login_username_wrong(self):
	pass

二、PageObject的简单使用

以百度为例,简单记录下pageobject进行自动化脚本设计的过程

1. 系统功能分析

实现的功能:

百度搜索
百度登录
百度注册

涉及的页面:

百度首页
搜索页面
登录页面
注册页面

页面的功能:
首页:搜索跳转、登录跳转
搜索:搜索功能
登录:登录功能、注册跳转
注册:注册功能

2. PO设计

根据功能分析中涉及的页面创建po
首页:index.py、搜索:search.py、登录:login.py、注册:register.py

根据页面中的功能编写po文件
首页:index.py

# 百度首页po
from selenium.webdriver.common.by import By

from page.login import Login
from selenium import webdriver

from page.search import Search


class Index:
	
	# 初始方法
    def __init__(self):
        self._driver = webdriver.Chrome()
        self._driver.get('https://www.baidu.com')
        self._driver.maximize_window()
        self._driver.implicitly_wait(3)

	# 退出方法
    def teardown(self):
        self._driver.quit()
	
	# 跳转登录
    def goto_login(self):
        self._driver.find_element(By.ID, 's-top-loginbtn').click()
        return Login(self._driver)
	
	# 跳转搜索
    def goto_search(self):
        return Search(self._driver)

搜索:search.py

from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver


class Search:

    def __init__(self, driver:WebDriver):
        self._driver = driver
	
	# 搜索功能封装
    def search(self):
        self._driver.find_element(By.ID, 'kw').send_keys('北京')
        self._driver.find_element(By.ID, 'su').click()

登录:login.py

from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver

from page.register import Register


class Login:
    def __init__(self, driver: WebDriver):
        self._driver = driver

    # 输入正确的账号和密码
    def login_success(self):
        self._driver.find_element(By.ID, 'TANGRAM__PSP_11__userName').send_keys('test123')
        self._driver.find_element(By.ID, 'TANGRAM__PSP_11__password').send_keys('Aa123456')
        self._driver.find_element(By.ID, 'TANGRAM__PSP_11__submit').click()

    # 输入错误的账号和密码
    def login_fail(self):
        self._driver.find_element(By.ID, 'TANGRAM__PSP_11__userName').send_keys('test123')
        self._driver.find_element(By.ID, 'TANGRAM__PSP_11__password').send_keys('Aa123456')
        self._driver.find_element(By.ID, 'TANGRAM__PSP_11__submit').click()
	
	# 跳转注册
    def goto_register(self):
        self._driver.find_element(By.ID, 'TANGRAM__PSP_11__regLink').click()
        windows = self._driver.window_handles
        self._driver.switch_to.window(windows[-1])
        return Register(self._driver)
	# 封装获取错误信息,用于后续断言实用
    def get_error_message(self):
        error_element = self._driver.find_element(By.ID, 'TANGRAM__PSP_11__error')
        error_value = error_element.text
        print(error_value)
        return error_value
     

注册:register.py

from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver


class Register:

    def __init__(self, driver: WebDriver):
        self._driver = driver
	# 注册功能封装
    def register(self):
        self._driver.find_element(By.ID, 'TANGRAM__PSP_4__userName').send_keys('test123')
        self._driver.find_element(By.ID, 'TANGRAM__PSP_4__phone').send_keys('13120991801')
        self._driver.find_element(By.ID, 'TANGRAM__PSP_4__password').send_keys('Aa123456')
        self._driver.find_element(By.ID, 'TANGRAM__PSP_4__verifyCode').send_keys('1234')
        self._driver.find_element(By.ID, 'TANGRAM__PSP_4__isAgree').click()
        self._driver.find_element(By.ID, 'TANGRAM__PSP_4__submit').click()

3. 测试用例设计

po设计完成后,创建测试类进行测试:test_baidu.py

from page.index import Index


class TestBaidu:
	# setup中实例化百度首页
    def setup(self):
        self.index = Index()
	# 登录成功测试
    def test_login_success(self):
        login = self.index.goto_login()
        login.login_success()
        self.index.teardown()
    
    # 登录失败测试
    def test_login_fail(self):
    	login = self.index.goto_login()
        login.login_fail()
        assert "用户名或密码有误,请重新输入或" in login.get_error_message()
        self.index.teardown()
        
	# 注册测试
    def test_register(self):
        self.index.goto_login().goto_register().register()
        self.index.teardown()
	# 搜索测试
    def test_search(self):
        self.index.goto_search()
        self.index.teardown()

总结

知识点总结:
1.不用每个po都进行初始化,在__init__方法中传入driver对象即可复用
2.页面跳转时不要忘了进行窗口的切换操作

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(十) web自动化测试-PO设计模式 的相关文章

  • GUI 测试工具 PyUseCase 与 Dogtail 相比如何?

    GUI测试工具如何Py用例 http pypi python org pypi PyUseCase重命名为故事文本 http pypi python org pypi StoryText 相比于Dogtail http en wikiped
  • 从所有数据帧列中删除子字符串

    我有一个单词列表 大约 1000 个单词 我称之为负面单词 CAST ARTICLES SANITARY JAN CLAUSES SPECIAL ENDORSEMENT 我很快就会用这个单词列表制作一个数据框 我还有一个数据框 看起来像 F
  • DynamodB:如何更新排序键?

    该表有两个键 filename 分区键 和eventTime 排序键 我要更新eventTime对于某些filename Tried put item and update item 发送相同的filename与新的eventTime但这些
  • 在 TestNG 中运行多个类

    我正在尝试自动化一个场景 其中我想登录一次应用程序 然后进行操作而无需再次重新登录 考虑一下 我有在特定类的 BeforeSuite 方法中登录应用程序的代码 public class TestNGClass1 public static
  • Python 不考虑 distutils.cfg

    我已经尝试了给出的所有内容 并且所有教程都指向相同的方向 即使用 mingw 作为 python 而不是 Visual C 中的编译器 我确实有 Visual C 和 mingw 当我想使用 pip 安装时 问题开始出现 它总是给Unabl
  • 使用 Tkinter 打开网页

    因此 我的应用程序需要能够打开其中的单个网页 并且它必须来自互联网并且未保存 特别是我想使用 Tkinter GUI 工具包 因为它是我最熟悉的工具包 最重要的是 我希望能够在窗口中生成事件 例如单击鼠标 但无需实际使用鼠标 有什么好的方法
  • Python speedtest.net,或等效的[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 是否有一个 Python 库可以实现 SpeedTest net 测试或等效的互联网连接速度测试 GitHub上有一个项目叫速度检查 https gi
  • NSUserNotificationCenter.defaultUserNotificationCenter() 使用 PyInstaller 返回 None

    我正在尝试将通知发送到通知中心 Mac OSX 我正在使用 PyObjC 绑定来使用我们的 python 应用程序中的 cocoa api 我正在使用以下代码片段 import Foundation import objc NSUserNo
  • Python 在哪些系统上不使用 IEEE-754 双精度浮点数

    Python 对 IEEE 754 浮点运算进行了各种引用 但不保证1 https docs python org 3 tutorial floatingpoint html 2 https pythondev readthedocs io
  • 在 django 中导入设置时出现奇怪的错误

    我有很多项目在 ubuntu 中使用 python2 7 和 virtualenv virtualenvwrapper 工作 在我的工作中 一些开发人员使用 macosx 和 windows 通常我像往常一样创建项目 django admi
  • 使用 ElementTree 在 python 中解析 xml

    我对 python 很陌生 我需要解析一些脏的 xml 文件 这些文件需要先清理 我有以下 python 代码 import arff import xml etree ElementTree import re totstring wit
  • 获取多个同名请求参数

    我的问题是给定的代码 from flask import Flask request app Flask name app route def hello return str request values get param None a
  • 如何创建增量加载网页

    我正在编写一个处理大量数据的页面 它会永远持续到我的结果页面加载 几乎无限 因为返回的数据太大了 因此 我需要实现一个增量加载页面 例如 url 中的页面 http docs python org http docs python org
  • 如何检测一个二维数组是否在另一个二维数组内?

    因此 在堆栈溢出成员的帮助下 我得到了以下代码 data needle s which is a png image base64 code goes here decoded data decode base64 f cStringIO
  • 从给定的项目列表创建子列表

    我首先要说的是以下问题不是为了家庭作业目的即使因为我几个月前就完成了软件工程师的工作 无论如何 今天我正在工作 一位朋友向我询问了这个奇怪的排序问题 我有一个包含 1000 行的列表 每行代表一个数字 我想创建 10 个子列表 每个子列表都
  • 如何将两列 pandas Dataframe 移动并堆叠为一列?

    我有一个下面提到的数据框 ETHNIC SEX USUBJID 0 HISPANIC OR LATINO F 16 1 HISPANIC OR LATINO M 8 2 HISPANIC OR LATINO Total 24 3 NOT H
  • AWS 将 MQTT 消息存储到 DynamoDB

    我构建了一个定期发送 MQTT 消息的 python 脚本 这是发送到后端的 JSON 字符串 Id 1234 Ut 1488395951 Temp 22 86 Rh 48 24 在后端 我想将 MQTT 消息存储到 DynamoDB 表中
  • PyQt5按钮lambda变量变成布尔值[重复]

    这个问题在这里已经有答案了 当我运行下面的代码时 它显示如下 为什么 x 不是 x 而是变成布尔值 这种情况仅发生在传递到用 lambda 调用的函数中的第一个参数上 错误的 y home me model some file from P
  • py2exe ImportError:没有名为 的模块

    我已经实现了一个名为 myUtils 的包 它由文件夹 myUtils 文件 组成 init py 和许多名称为 myUtils 的 py 文件 该包包含在 myOtherProject py 中 当我从 Eclipse 运行它们时可以找到
  • 使用 python 将 CSV 文件上传到 Microsoft Azure 存储帐户

    我正在尝试上传一个 csv使用 python 将文件写入 Microsoft Azure 存储帐户 我已经发现C sharp https blogs msdn microsoft com jmstall 2012 08 03 convert

随机推荐

  • ​外包公司干了不到3个月,我离职了...(防坑指南)

    外包公司干了不到3个月 我离职了 当项目快要做完的时候 我就担心自己是不是要被 释放了 直到外包HR wx找我聊项目 我就不担心了 结果确实是要被 释放 从杭州到深圳 来的也突然 离职也有点突然 也是意料之中 本来想写 年终总结 结果现在要
  • Java五子棋

    提示 本人大二时的java大作业 当时没有学数据库 只是学到界面哪里 所以做出的条件有限 哈哈 看看就好 有帮助了 就拿走 不谢 Java五子棋 前言 主要就是涉及到java界面编程 实现Runable接口重写run方法 实现多线程 来控制
  • SQL中declare申明变量

    原文地址 http blog csdn net yanpingsz article details 5633660 在sql语句中添加变量 declare local variable data type 声明时需要指定变量的类型 可以使用
  • python定时运行,多进程

    可以通过另开一条线程 去专门做这件事情 py2代码如下 如果是py3请自行调整下语法 coding utf8 import threading import time 真正要执行的函数 def t1 print ok 每隔10秒钟执行 de
  • 五大车载操作(VOS)系统优劣对比,车载系统架构分析-QNX系统性能分析

    如果你认为本系列文章对你有所帮助 请大家有钱的捧个钱场 点击此处赞助 赞助额0 1元起步 多少随意 声明 本文只用于个人学习交流 若不慎造成侵权 请及时联系我 立即予以改正 锋影 email 174176320 qq com 导读 车载操作
  • UART、TTL和RS232的区别

    UART TTL和RS232的区别 串行通信 UART TTL RS232 学习硬件的开始接触的就是串口 但是一直没搞懂UART TTL和RS232这些的关系 总感觉相互之间有所交叉 无法完全区分开 于是有了这篇博文 但是 这篇博文自我感觉
  • 分离轴定理(SAT):凸多边形相交检测

    引言 在计算机图形学 游戏开发 碰撞检测等领域 凸多边形相交检测是一个常见而重要的问题 为了快速准确地判断两个凸多边形是否相交 分离轴定理 Separating Axis Theorem 简称 SAT 成为了一种高效而可靠的算法 本文将深入
  • css里各个元素的书写顺序

    1 位置相关 position top left index float display 2 大小相关 width height margin padding 3 文字相关 font line height color letter spa
  • Python 怎么利用Python绘制二元高次隐函数的函数图像及其极值点——以某双核论文模型方程为例

    项目场景 几日前 在研究某双核期刊的某篇论文时 发现论文上的函数图像绘制得似乎有些不精确 原函数方程为 0 2045 y 2 3 4 y 3 2 x y 2 0 45 2 0 论文原文中函数图像如下图 问题描述 可以很明显地看出 极值点附近
  • Gof23设计模式之模板方法模式

    1 定义 定义一个操作中的算法骨架 而将算法的一些步骤延迟到子类中 使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤 2 结构 模板方法 Template Method 模式包含以下主要角色 抽象类 Abstract Clas
  • execjs随心所欲运行抠出来的js代码:报错什么都不是问题 execjs._exceptions.ProgramError: ReferenceError: $ is not defined

    起因 今天扣出一段js想用execjs执行 报错 未定义 也就是说execjs不能执行jquery 决定试试用nodejs来执行 execjs exceptions ProgramError ReferenceError is not de
  • Windows10 安装 Vue3

    一 安装Node js 官网下载Node js https nodejs org en download 下载完成后 双击 msi文件 将默认安装路径按照喜好修改 其余的设置默认即可 不需要勾选安装的附加选项 node v 二 更新Node
  • lattice

    lattice 在实际的语音识别系统中 最优路径不一定与实际字序列匹配 我们一般希望能够得到得分最靠前的多条候选路径 即N best 为了紧凑地保存候选路径 我们一般采用lattice 词图 来保存识别的候选序列 lattice本质上是一个
  • Ubuntu18.04上安装RTX 2080Ti显卡驱动

    文章目录 1 安装Linux系统 1 1下载Linux镜像文件 1 2 制作系统盘 1 3 安装Linux系统 1 4 配置linux系统 2 安装英伟达显卡驱动 2 1 预备工作 2 2 安装显卡驱动 3 安装cuda 4 安装cudnn
  • 代数余子式的几何意义,点积和叉乘的几何意义

    1 点乘的几何意义 a b c d e f ad be cf 结果是一个标量 也可以写为 a b a b cos 以下说明点乘的几何意义 就是一个向量在另一个单位向量 如果另一个向量是单位向量 上的投影长度 a b b a cos a b
  • thinkphp5.1开发app接口版本控制(路由设置)

    使用thinkphp5 1开发app接口进行版本控制 在index controller下创建v1和v2目录 v1下创建版本1的文件 如下图 在route route php中 如下图 v获取版本例如 v1 v2 下面第一个路由其实是 接口
  • 如何为服务网格选择入口网关_如果使用服务网格,是否需要API网关?

    如何为服务网格选择入口网关 这篇文章可能无法突破API网关和Service Mesh周围的噪音 但是 这是2020年 围绕这些主题仍然存在很多困惑 我选择编写此内容是为了帮助带来真正的具体解释 以帮助阐明差异 重叠之处以及何时使用它们 如果
  • 前缀树(字典树)应用——实现 Trie (前缀树)、添加与搜索单词

    目录 1 前缀树原理简介 2 实现前缀树 2 1 题目描述 2 2 题目分析 2 3 代码实现 3 添加与搜索单词 3 1 题目描述 3 2 题目分析 3 3 代码实现 4 总结 1 前缀树原理简介 先来简单介绍一下前缀树是什么 前缀树也叫
  • python--爬虫 爬取html和txt文件

    一 python爬取html文件 使用python爬取某网站首页并下载html文件 下面介绍两种方式 一种是urllib 另一种是requests 1 使用urllib import urllib request url http www
  • (十) web自动化测试-PO设计模式

    十 web自动化测试 PO设计模式 文章目录 十 web自动化测试 PO设计模式 前言 一 PageObject原则 1 使用方法代替页面的功能点 2 case中不要过多暴露页面的细节 3 po本身不进行断言 4 一个方法返回另一个页面 P