一文详解Python中PO模式的设计与实现

2023-12-20

在使用 Python 进行编码的时候,会使用自身自带的编码设计格式,比如说最常见的单例模式,稍微抽象一些的抽象工厂模式等等… 在利用 Python 做自动化测试的时候,是不是也有自己的设计模式呢?所以在今天这个小章节里,需要续了解的就是 python 作为自动化测试里面的一种设计模式,尤其是 UI自动化 的专属模式 —> “PageObject” 自动化设计模式,简称 “PO模式” 。

了解并实现 “PageObject” 自动化设计模式

什么是PO模式

一种在测试自动化中变得流行的设计模式,使得自动化测试脚本的代码量减少,避免代码重复,更加易读,减少维护的成本。

其实简单来说就是将页面的操作、脚本的Case、通用的页面元素分开的这样一个模式。

一般 PO 设计模式多数分为三层

PO 三层模式

第一层:(核心、BasePage层)

  • 对 Selenium 的底层进行二次封装,定义一个所有页面都继承的基础属性页面 —> BasePage 。
  • 封装 Selenium 的基本方法,例如:元素定位、元素等待、导航页面、页面跳转等等...
  • PS:其实在使用的过程中不需要全部封装,用到多少方法就封装多少方法即可。(之前接触过其他大佬的自动化框架,他把所有的 selenium 的底层的方法做了一层封装,这样做很好,能够做很多的事情,但是比较繁重。实际上在真实使用的时候用不到那么多,所以不建议全部封装)。

第二层:(页面层、也叫配置层)

  • 页面元素进行分离,每个元素只定位一次,隔离定位。如果页面改变,只需要改变相应的元素定位。
  • 如果存在一些业务的属性、方法,需要将其通过业务方法的方式将业务与操作元素的动作分离开来。

第三层:(封装测试层)

使用单元测试框架对业务逻辑进行封装测试

PO 设计模式的优点

UI 页面的频繁变化,导致页面 UI 元素频繁的变动,PO设计模式便于元素定位改变的维护。

传统线性自动化,多个用例脚本中需要反复的定位同一个元素,PO设计模式可以减少这部分频繁定位元素的代码量

小节:减少重复代码的冗余,便于UI页面频繁变更下的元素定位维护。

将改写的脚本转为PO设计模式

首先在项目里创建一个 python package 命名为 pages ,然后在 pages 创建一个模块 base_page.py 用来作为第一层的 base_page核心层 。

如下图:

构建基础的 BasePage 层

尝试构建最基础的 base_page 层,代码示例如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

# coding:utf-8

from selenium import webdriver

class BasePage( object ):

"""

1、第一层 - 核心层-BasePage层,定义一个所有页面都继承的page层

2、对将要使用的 selenium 的底层方法进行二次封装

"""

def __init__( self , driver, path = None ): # 构造函数,类的初始化

"""

为了方便编写将 driver 初始化,

先使用 "self.driver = webdriver.Chrome()" 后续改为 self.driver = driver

"""

self .driver = webdriver.Chrome()

# self.driver = driver

self .driver.implicitly_wait( 5 ) # 定义全局的默认加载时间

self .load_page(path) # 访问并加载网页

def load_page( self , path = None ): # 访问并加载网页,如果 path 不为空的话,直接传给 driver.get() 访问

if path is not None :

self .driver.get(path)

def by_xpath( self , xpath): # 二次封装 selenium 的 xpath 元素定位

return self .driver.find_element_by_xpath(xpath)

def js_click( self , xpath): # JavaScript 定位元素,并执行 click

self .driver.execute_script( 'arguments[0].click()' , self .by_xpath(xpath))

到这里,base_page 层算是写完了,这就是一个最底层、最基础的类,这个类让我们实现了 selenium 底层的 Xpath 定位方法 与 JavaScript 定位元素方法,这些方法能够帮助我们更好的去完成后续的定位处理操作。

ok,接下我们再去编写各个页面层的东西。

构建首页的 Page 层(HomePage)

代码示例如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# coding:utf-8

from selenium import webdriver

from pages.base_page import BasePage # 导入 base_page 层

class HomePage(BasePage): # 定义 FirstPage(继承 BasePage )

"""

1、第二层 - 各个页面单独封装成层,页面的元素、操作、流程

"""

def direct_to_login( self ): # 首页跳转至登录页

return self .by_xpath( "//*[@id='app']/div[1]/div[5]/div[3]" )

def direct_to_product( self ): # 登陆成功后,跳转至首页

return self .by_xpath( "//*[@id='app']/div[1]/div[5]/div[1]" )

# 方法流程

def cross_to_login( self ):

self .direct_to_login().click() # 点击 "登录" 按钮进行登录

def cross_to_product( self ):

self .direct_to_product().click() # 点击 "首页" 跳转至首页

构建登录页的 Page 层(LoginPage)

代码示例如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

# coding:utf-8

from selenium import webdriver

from pages.base_page import BasePage # 导入 base_page 层

class LoginPage(BasePage): # 定义 FirstPage(继承 BasePage )

"""

1、页面层(登录页) - 各个页面单独封装成层,页面的元素、操作、流程

"""

def login_username( self ): # 登录页 - 用户名输入框

return self .by_xpath( "//*[@id='app']/div[1]/form/div[1]/div[2]/div/input" )

def login_password( self ): # 登录页 - 密码输入框

return self .by_xpath( "//*[@id='app']/div[1]/form/div[2]/div[2]/div/input" )

def login_button( self ): # 登录页 - 登录按钮

return self .by_xpath( "//*[@id='app']/div[1]/form/div[3]/button" )

# 登录Case

def login( self , username, password): # 登录方法,传入 username 与 password

self .login_username().send_keys(username)

self .login_password().send_keys(password)

self .login_button().click()

构建 首页 - 订单 - 支付 流程的 Page 层(OrderPage)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

# coding:utf-8

from time import sleep

from pages.base_page import BasePage # 导入 base_page 层

class OrderPage(BasePage): # 定义 FirstPage(继承 BasePage )

"""

1、页面层(登录页) - 各个页面单独封装成层,页面的元素、操作、流程

"""

def product( self ): # 下单 - 第一个产品

return self .by_xpath( "//*[@id='app']/div[1]/div[4]/div[2]/a[1]" )

def ticket_book( self ): # 门票 - 预定(按钮)

return self .by_xpath( "//*[@id='app']/div[1]/div[5]/div[2]/div[2]/a" )

def book_date( self ): # 门票 - 选择日期

return self .by_xpath( "//*[@id='app']/div[1]/form/div[1]/div[1]/div[2]/div/input" )

def to_order( self ): # 门票下单

return self .by_xpath( "//*[@id='app']/div[1]/form/div[4]/div/button" )

def pay_off( self ): # 门票下单 - 支付

return self .by_xpath( "//*[@id='app']/div[1]/form/div/div/button" )

def confirm( self ): # 门票下单 - 确认支付

return self .by_xpath( "/html/body/div[5]/div[3]/button[2]" )

# 下单成功Case

def place_order( self ):

self .product().click()

self .ticket_book().click()

self .book_date().send_keys( "2022-06-16" )

self .to_order().click()

sleep( 2 )

element = self .pay_off()

self .driver.execute_script( 'arguments[0].click()' , element)

sleep( 2 )

以上,我们准备的所有页面需要准备的元素定位、基线流程算是写完了,但是具体的用例,应该如何实现呢?继续往下看。

PO 设计模式下测试Case的改造

代码示例如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

# coding:utf-8

import unittest

from time import sleep

from selenium import webdriver

from pages.home_page import HomePage

from pages.login_page import LoginPage

from pages.order_page import OrderPage

'''

1、初始化 - 打开浏览器,设置浏览器大小

2、最终操作 - 关闭浏览器

3、用例部分 - 登录 与 购买操作、下订单、支付

'''

class TestTravel(unittest.TestCase):

@classmethod

def setUpClass( cls ): # 每个测试类在加载之前执行一次 setUpClass ,初始化方法

cls .driver = webdriver.Chrome()

cls .driver.maximize_window()

def test_a_order( self ):

#初始化参数

username = '13500000001'

password = 'Success@2020'

#初始化界面

home_page = HomePage(driver = self .driver, path = "http://django.t.mukewang.com/#/" )

login_page = LoginPage(driver = self .driver)

order_page = OrderPage(driver = self .driver)

#跳转登录

home_page.cross_to_login()

#登录

login_page.login(username, password)

# 跳转至订单页

home_page.cross_to_product()

#下单

order_page.place_order()

@classmethod

def tearDownClass( cls ):

cls .driver.quit() # 彻底退出浏览器

if __name__ = = '__main__' :

unittest.main()

这里改造完成之后,记得将 "BasePage 层" 的 '# self.driver = driver' 取消注释,并将 'self.driver = webdriver.Chrome()' 注释掉 。

以上就是一个比较完整的通过 PO 的方式来连接三个页面与基础的 base_page 来写出的更简洁一些的测试用例。

运行结果如下:(速度可能过快,担待一下,gif 只有15秒的时间)

​现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:485187702【暗号:csdn11】

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 希望能帮助到你! 【100%无套路免费领取】

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

一文详解Python中PO模式的设计与实现 的相关文章

随机推荐

  • Python+Pytest接口自动化之测试函数、测试类/测试方法的封装

    前言 在python pytest 接口自动化系列中 我们之前的文章基本都没有将代码进行封装 但实际编写自动化测试脚本中 我们都需要将测试代码进行封装 才能被测试框架识别执行 例如单个接口的请求代码如下 import requests he
  • Amazon Toolkit — CodeWhisperer 使用

    tFragment gt 官网 https aws amazon com cn codewhisperer trk cndc detail 最近学习了亚马逊云科技的 代码工具 感慨颇多 下面是安装 和使用的分享 CodeWhisperer
  • android 13.0 USB连接模式默认设为MTP

    1 概述 在13 0android系统产品开发中 在通过otg连接设备的时候 会弹出usb连接模式这时候会让客户选择当前连接电脑是 哪种模式 在项目开发中 需要以mtp模式 就是可以在电脑查看设备的内部存储的样式来设置otg连接电脑的模式
  • 数据工作者最爱的AI功能,你知道吗~

    在工作中难以避免的一项任务就是各种数据总结和汇报 怎么分析总结 以何种形式汇报 都是具有一定的难点 所以我要推荐的就是具有AI图表解析功能的可视化工具 Easyv数字孪生低代码可视化平台 可实现对数据的可视化展示 通过丰富的图表组件 清晰展
  • CentOS7.9安装Mysql5.7-m14

    简介 本文介绍了Linux CentOS系统下Mysql5 7 m14的下载和安装方法 环境 CentOS Linux release 7 9 2009 Core mysql Ver 14 14 Distrib 5 7 4 m14 for
  • EasyV+UE创造数字孪生可视化新篇章!

    众所周知 UE是UNREAL ENGINE 虚幻引擎 的简写 由Epic开发 是世界知名授权最广的游戏引擎之一 EasyV是一款数据可视化应用平台 用户通过EasyV可以更高效的实现数据可视化项目搭建 产品内有丰富的模版 海量的组件 简单的
  • 智能辅助技术的未来前景:创新与便利的引领者

    在数字化时代 智能辅助技术正迅速崛起 成为改善生活 提升工作效率的关键因素 这些技术通过结合人工智能 机器学习和物联网等前沿技术 为用户提供更加智能 便捷的体验 未来 智能辅助技术有望在多个领域引领创新 改变人们的生活方式 1 智能助理的个
  • 使用 Amazon Fault Injection Service 演示多区域和多可用区应用程序弹性

    文章作者 Jeff Amazon Fault Injection Service FIS 可帮助您将混沌工程大规模付诸实践 今天 我们推出了新的 场景 这些场景可以让您演示在亚马逊云科技可用区完全断电 或从一个亚马逊云科技区域到另一个亚马逊
  • 测试开发 | 物流与供应链中的智能优化

    随着全球化的深入和商业环境的复杂化 物流与供应链管理面临着前所未有的挑战 然而 随着人工智能 AI 和物联网 IoT 等技术的不断发展 智能优化正成为推动物流与供应链行业变革的关键力量 以下是智能优化在物流与供应链领域的一些关键应用 1 实
  • 测试开发 |AI驱动的健康监测与管理:数字化时代的医疗创新

    随着人工智能 AI 技术的飞速发展 其在健康监测与管理领域的应用正日益成为医疗领域的重要变革力量 AI不仅提供了更精准 高效的医学诊断手段 还为个体化的健康管理提供了全新的可能性 以下是AI驱动的健康监测与管理在数字化时代的一些关键应用 1
  • 测试开发 | 游戏开发中的人工智能创新:探索数字娱乐的未来

    随着科技的不断进步 人工智能 AI 在游戏开发领域展现出巨大的潜力 为游戏行业带来了前所未有的创新 以下是游戏开发中人工智能创新的一些关键方面 1 智能敌对角色和游戏对抗性 传统游戏中的敌对角色往往遵循固定的模式和策略 容易被玩家预测 通过
  • 跟着野火学FreeRTOS:第一段(任务定义,切换以及临界段)

    在裸机系统中 系统的主体就是 C P U CPU CP U 按照预先设定的程序逻辑在 m a i n
  • git命令github拉取推送代码超时报错

    背景 使用魔法科学上网之后 github的页面可以正常访问 但是拉取代码和推送代码还是一直报错 报错信息内容 Failed to connect to github com port 443 Timed out 其实本质是因为代理设置的不正
  • LLama Factory 安装部署实操记录(二)

    1 项目地址 GitHub hiyouga LLaMA Factory Easy to use LLM fine tuning framework LLaMA BLOOM Mistral Baichuan Qwen ChatGLM Easy
  • 从学到考,一图带你读懂开发者技能成长秘籍

    亚马逊云科技开发者社区 为开发者们提供全球的开发技术资源 这里有技术文档 开发案例 技术专栏 培训视频 活动与竞赛等 帮助中国开发者对接世界最前沿技术 观点 和项目 并将中国优秀开发者或技术推荐给全球云社区 如果你还没有关注 收藏 看到这里
  • C++ 字符串比较------strcmp函数和strncmp函数

    strcmp 函数原型 int strcmp const char str1 const char str2 功能 strcmp函数会按照字典顺序逐个比较两个字符串的字符 直到遇到不同的字符或者遇到字符串结束符 0 返回值 该函数返回值如下
  • LLama Factory 实操记录(一)

    1 api端口参数说明 src api h help 显示帮助信息并退出 model name or path MODEL NAME OR PATH 模型权重的路径或标识符 来自 huggingface co models 或 models
  • 开班在即 | 测试开发线下高薪私教班助力你的职场晋升

    深圳线下高薪私教班即将结束 很多同学都实现了跳槽涨薪的目标 今天和大家分享其中一位同学的求职成果 她成功斩获了4个名企Offer 并且薪资从25W涨到了40W 她自己对这个结果很满意 我们也为她感到高兴 现在 我们推荐她所选择的班型给大家
  • 高通切换到Emergency Download:adb reboot edl

    刷机 开机下adb reboot edl 切到QDloader 9008 点下载 The command adb reboot edl is used to reboot an Android device into EDL Emergen
  • 一文详解Python中PO模式的设计与实现

    在使用 Python 进行编码的时候 会使用自身自带的编码设计格式 比如说最常见的单例模式 稍微抽象一些的抽象工厂模式等等 在利用 Python 做自动化测试的时候 是不是也有自己的设计模式呢 所以在今天这个小章节里 需要续了解的就是 py