UI自动化测试中公认最佳的设计模式-POM

一、概念

什么是POM?

POM是PageObjectModule(页面对象模式)的缩写,其目的是为了Web UI测试创建对象库。在这种模式下,应用涉及的每一个页面应该定义为一个单独的类。类中应该包含此页面上的页面元素对象和处理这些元素对象所需要的方法等。将流程所关联的页面作为对象,将对象串联起来,形成一个个不同的流程,POM是业内公认最佳的设计模式。

POM的优点:

(1)PO提供了页面元素操作和业务流程相分离的模式,可以使测试的代码结构比之前清晰,可读性强。

(2)更方便地复用对象和方法。

(3)对象库是独立于测试用例的、统一的对象库,可以通过集成不同的工具类来达到不同的测试目的。比如集成UnitTest可以用来做单元测试、自动化/功能测试,同时也可以集成JBehave/Cucumber等来做验收测试。

(4)使得整体自动化测试的优点变得更容易一些,如果有某个页面的元素需要变更,那么就可以直接更改封装好的页面元素类即可,而不用更改调用它的其他测试类/代码。这样整个的代码维护成本也会缩减。

PO的核心就是分层思想,把同属于一个页面的元素都放在一个页面类中。

以上概念内容来源于某书籍

二、简要结构设计

  1. 逻辑代码:基类,实现所有工具函数封装,类似于关键字驱动设计模式;

  2. 页面对象代码:基于系统页面,通过调用工具函数来实现业务的操作,生成对应的页面对象;

  3. 测试代码:基于测试需要,组件页面对象,实现核心流程的自动化,执行测试用例;

  4. 测试数据:为测试用例的执行提供所需要的测试数据。

三、POM完整框架

  1. Base层:定义项目需要的基础方法,特别是一些基础操作,如元素click操作、sendkeys操作,调用JavaScript脚本的方法和其他一些与基本浏览器相关的操作。

  2. Common层:包含处理Excel文件的方法,获取项目路径、测试系统URL的信息和框架执行相关日志功能的实现方法。

  3. Data层:存放测试数据,在这里可以维护测试数据,这样存放是为了让项目的可维护性强、整体的条理性强。测试数据有时是自动化测试的驱动因素,因此对Data的管理和维护就显的特别重要。

  4. Logs层:存放项目在运行过程中产生的日志文件。

  5. PageObject层:这里是PO的核心层,该层不但涉及代码技术,还涉及对项目业务的分析,进而对项目的页面进行分析。

  6. Reports层:存放项目执行过程中产生的测试报告文件,测试报告是对测试结果的总结。

  7. TestCase层:管理测试用例和执行测试,相当于测试的总入口。

  8. config.ini:整个项目需要用到的配置项。

四、项目实战

以百度搜索为例

  1. 我们首先新建一个简单的项目结构:base、data、page_object、cases,如下图所示:

image.png

2. 在base包下新建一个base_page.py文件,在base_page.py文件下新建一个BasePage类作为基类,提供各个常用的已封装好的函数,便于后续的页面对象类进行调用。selenium中常用的函数:元素定位、输入、点击、访问URL、等待、关闭等。代码如下:

  1. '''

  2. 基类:提供各个常用的已封装好的函数,便于后续的页面对象类进行调用。

  3. selenium中常用的函数:元素定位、输入、点击、访问URL、等待、关闭

  4. '''

  5. from time import sleep

  6. from selenium import webdriver

  7. class BasePage:

  8. driver = webdriver.Chrome()

  9. # 访问URL

  10. def visit(self, url):

  11. self.driver.get(url)

  12. # 元素定位

  13. def locator(self, loc):

  14. return self.driver.find_element(*loc)

  15. # 输入

  16. def input(self, loc, txt):

  17. self.locator(loc).send_keys(txt)

  18. # 点击

  19. def click(self, loc):

  20. self.locator(loc).click()

  21. # 等待

  22. def wait(self, time):

  23. sleep(time)

  24. # 关闭

  25. def close(self):

  26. self.driver.quit()

  1. page_object包下新建一个search_page.py文件,在该文件下新建一个SearchPage类继承BasePage类,调用基础类中的方法实现页面操作,生成对应的页面对象。代码如下:
  2. '''

  3. 百度查询页面,搜索功能

  4. '''

  5. from selenium.webdriver.common.by import By

  6. from base.base_page import BasePage

  7. from selenium import webdriver

  8. class SearchPage(BasePage):

  9. url = 'http://www.baidu.com'

  10. # 定位百度输入框

  11. search_input = (By.NAME, 'wd')

  12. # 定位百度一下按钮

  13. search_button = (By.ID, 'su')

  14. # 封装实现业务流程的函数

  15. def search(self, txt):

  16. self.visit(self.url)

  17. self.wait(2)

  18. self.input(self.search_input, txt)

  19. self.wait(2)

  20. self.click(self.search_button)

  1. cases包下新建一个testcase.py文件作为测试类,实现在百度中分别搜索selenium、python,代码如下:
  2. '''

  3. 测试类

  4. '''

  5. import unittest

  6. from page_object.search_page import SearchPage

  7. from selenium import webdriver

  8. class Case(unittest.TestCase):

  9. def test_search1(self):

  10. driver = webdriver.Chrome()

  11. txt = 'selenium'

  12. SearchPage(driver).search(txt)

  13. def test_search2(self):

  14. driver = webdriver.Chrome()

  15. txt = 'python'

  16. SearchPage(driver).search(txt)

  17. if __name__ == '__main__':

  18. unittest.main()

运行以上代码发现,因为创建了两次webdriver,所以每运行一次代码都会打开一个Chrome浏览器,同时,代码中也存在冗余。优化方案:可以增加@classmethod作为前置条件和后置条件,搜索的条件也可以采用数据驱动的方式完成,提高代码的可读性与维护性。

data包下新建一个searchTXT.yaml文件,存放搜索的内容如下:

image.png

优化之后代码如下:

  1. '''

  2. 测试类

  3. '''

  4. import unittest

  5. from page_object.search_page import SearchPage

  6. from selenium import webdriver

  7. import ddt

  8. @ddt.ddt()

  9. class Case(unittest.TestCase):

  10. @classmethod

  11. def setUpClass(cls) -> None:

  12. cls.driver = webdriver.Chrome()

  13. cls.se = SearchPage(cls.driver)

  14. @classmethod

  15. def tearDownClass(cls) -> None:

  16. cls.driver.quit()

  17. @ddt.file_data('../data/searchTXT.yaml')

  18. def test_search(self, txt):

  19. self.se.search(txt)

  20. if __name__ == '__main__':

  21. unittest.main()

运行以上代码,发现测试用例执行了四次,分别搜索了selenium、python、java、php,如此实现了数据驱动,同时也在一个浏览器中完成了操作。

五、后记

以上简单的实现了POM的设计模式,完成了基类、页面对象层、数据层、测试层的代码编写,若读者有兴趣,可以完成报告层、日志层等内容的编写,最终实现完整的框架。

 感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

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

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

相关文章

单片机(STM32)开发中常用的C语言基础语法(二)

9、goto语句与标签 goto语句用于无条件地转移到程序中的另一部分。它通常用于跳出循环或提前退出函数。然而,使用goto语句需要谨慎,因为过度使用它可能会导致代码难以理解和维护。 标签(Label)是一个代码标识符,后面…

柯西变异和正余弦改进的麻雀搜索算法及python实现

目录 柯西变异和正余弦改进的麻雀搜索算法第一部分:麻雀搜索算法概述1.1 麻雀搜索算法简介1.2 算法特点1.3 算法流程1. 初始化阶段2. 觅食者搜索阶段3. 监视者逃逸阶段4. 判断收敛条件1.4 公式描述第二部分:改进方法——柯西变异与正余弦机制2.1 改进思路2.2 柯西变异公式2.3…

Scala文件读写——成绩分析

根据文件解决下例问题 1.读入txt文件:按行读入 import scala.io.Sourceobject Test文件读写_成绩分析 {def main(args: Array[String]): Unit {//1.按行读入val source Source.fromFile("score.txt")val it source.getLines()it.next()//跳过第一行wh…

C# Winform 俄罗斯方块小游戏源码

文章目录 1.设计来源俄罗斯方块小游戏讲解1.1 主界面1.2 游戏界面1.3 游戏结束界面1.4 配置游戏界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板,程序开发,在线开发,在线沟通 作者:xcLeigh 文章地址:https:…

前端框架Vue3——响应式数据,v-on,v-show和v-if,v-for,v-bind

Vue的定义为渐进式的JavaScript框架。所谓渐进式,是指其被设计 为可以自底向上逐层应用。我们可以只使用Vue框架中提供的某层的功 能,也可以与其他第三方库整合使用。当然,Vue本身也提供了完整的 工具链,使用其全套功能进行项目的…

实验二 系统响应及系统稳定性

实验目的 (1)学会运用Matlab 求解离散时间系统的零状态响应; (2)学会运用Matlab 求解离散时间系统的单位取样响应; (3)学会运用Matlab 求解离散时间系统的卷积和。 实验原理及实…

.NET Core发布网站报错 HTTP Error 500.31

报错如图: 解决办法: 打开任务管理器》》服务》》找到这仨服务,右键启动即可,如果已经启动了就重启:

FFmpegFrameRecorder 切分视频文件时结束条件设置不当导致切分后的文件过短问题

问题 下游反馈使用 ffmpeg 切割后的音频文件,无法正确识别其声音的性别 排查流程 1,由于线上大部分用户上传音频后,进行切分后的音频都没问题,因此考虑到这些无法识别性别的音频,有格式问题,需要找出其共…

真题-桂城2018年六年级

01.整点 题目描述 在二维坐标系, 有一个圆&#xff0c;圆心在(0,0)&#xff0c;圆的半径是r。问圆内有多少个整点(所谓的整点就是横坐标和纵坐标都是整数的点)。 若点P的横坐标是整数a&#xff0c;纵坐标是整数b&#xff0c;那么只要满足aa bb < r*r, 那么P就是圆内的整点…

【快捷入门笔记】mySQL基本操作大全-运算符和句子

一、ORDER BY 排序 排序方式 1.升序&#xff1a;ASC&#xff08;默认就是升序&#xff09; 2.降序&#xff1a;DESC 3.如果有多个排序条件&#xff0c;前面的值一样时才会判断第二条件 --按照数学成绩排序 select*from Student ORDER BY math --按照数学成绩排序&#xff0c;…

麒麟安全增强-kysec

DAC: 自主访问控制是linux下默认的接入控制机制,通过对资源读、写、执行操作,保证系统安全 MAC:安全接入控制机制,由操作系统约束的访问控制,默认情况下,MAC不允许任何访问,用户可以自定义策略规则制定允许什么 ,从而避免很多攻击。 MAC强制访问控制常见的实现方式:…

java多线程——synchronized的偏向锁、轻量级锁和重量级锁

在Java中&#xff0c;synchronized关键字是用于实现线程同步的一种机制&#xff0c;它提供了偏向锁、轻量级锁和重量级锁三种锁状态来优化同步性能。以下是这三种锁的原理和使用方法的详细解释&#xff1a; 一、偏向锁&#xff08;Biased Locking&#xff09; 原理 偏向锁的目…

Otter 安装流程

优质博文&#xff1a;IT-BLOG-CN 一、背景 随着公司的发展&#xff0c;订单库的数据目前已达到千万级别&#xff0c;需要进行分表分库&#xff0c;就需要对数据进行迁移&#xff0c;我们使用了otter&#xff0c;这里简单整理下&#xff0c;otter 的安装过程&#xff0c;希望对…

速盾:ddos防御手段哪种比较好?高防cdn怎么样?

DDoS&#xff08;分布式拒绝服务&#xff09;攻击是一种威胁网络安全的常见攻击手段。为了保护网站和服务器免受DDoS攻击的影响&#xff0c;许多安全专家和公司开发了各种防御手段。在这篇文章中&#xff0c;我们将重点讨论一种常见的DDoS防御手段——高防CDN&#xff08;内容分…

faiss VS ChromaDB

faiss faiss 是一个开源的机器学习库&#xff0c;由Facebook AI Research&#xff08;FAIR&#xff09;开发&#xff0c;主要用于高效的大规模向量搜索和聚类。 faiss 的核心优势在于它为高维向量空间中的数据提供了快速的近似最近邻搜索&#xff08;ANNS&#xff09;算法&am…

微信小程序导航方式详解:声明式导航与编程式导航

微信小程序导航方式详解:声明式导航与编程式导航 引言 在微信小程序的开发中,页面导航是实现用户交互的重要组成部分。小程序提供了两种主要的导航方式:声明式导航和编程式导航。了解这两种导航方式的特点、使用场景及其优缺点,对于提升小程序的用户体验和开发效率至关重…

如何解决Jupyter command `jupyter-contrib` not found.

目录 (base) C:\Users\hello>pip show jupyter_contrib_nbextensions Name: jupyter-contrib-nbextensions Version: 0.7.0 Summary: A collection of Jupyter nbextensions. Home-page: https://github.com/ipython-contrib/jupyter_contrib_nbextensions.git Author: ipyt…

Gitee markdown 使用方法(持续更新)

IPKISS 获取仿真器件的名称 引言正文标题换行第一种------在行末尾手动键入两个空格第二种------额外换行一次&#xff0c;即两行中间留一个空行 缩进与反缩进代码块行内代码添加图片添加超链接 加粗&#xff0c;倾斜&#xff0c;加粗倾斜 引言 有些保密性的文件或者教程&…

Adobe Illustrator 2024 安装教程与下载分享

介绍一下 下载直接看文章末尾 Adobe Illustrator 是一款由Adobe Systems开发的矢量图形编辑软件。它广泛应用于创建和编辑矢量图形、插图、徽标、图标、排版和广告等领域。以下是Adobe Illustrator的一些主要特点和功能&#xff1a; 矢量绘图&#xff1a;Illustrator使用矢量…

golang学习5

为结构体添加方法 异常处理过程