1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 〖Python WEB 自动化测试实战篇⑫〗- 实战 - PageObject框架设计(亦叫做 “页面对象” 模式)

〖Python WEB 自动化测试实战篇⑫〗- 实战 - PageObject框架设计(亦叫做 “页面对象” 模式)

时间:2024-01-22 14:56:43

相关推荐

〖Python WEB 自动化测试实战篇⑫〗- 实战 - PageObject框架设计(亦叫做 “页面对象” 模式)

前言

✌ 作者简介:渴望力量的哈士奇 ✌,大家可以叫我 🐶哈士奇🐶 ,一位致力于 TFS 赋能的博主 ✌

🏆 CSDN博客专家认证、新星计划第三季全栈赛道 top_1 、华为云享专家、阿里云专家博主 🏆

📫 如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀

💬 人生格言:优于别人,并不高贵,真正的高贵应该是优于过去的自己。💬

🔥 如果感觉博主的文章还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主哦

文章目录

🐳 什么是〖 PO模式 〗🐬 PO 三层模式🐬 PO 设计模式的优点🐳 将改写的脚本转为 PO 设计模式🐬 构建基础的 BasePage 层🐬 构建首页的 Page 层(HomePage)🐬 构建登录页的 Page 层(LoginPage)🐬 构建 首页 - 订单 - 支付 流程的 Page 层(OrderPage)🐳 PO 设计模式下测试Case的改造

在使用 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 层,代码示例如下:

# coding:utf-8from selenium import webdriverclass 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 = driverself.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 定位元素,并执行 clickself.driver.execute_script('arguments[0].click()', self.by_xpath(xpath))

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

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

🐬 构建首页的 Page 层(HomePage)

代码示例如下:

# coding:utf-8from selenium import webdriverfrom 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)

代码示例如下:

# coding:utf-8from selenium import webdriverfrom 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")# 登录Casedef login(self, username, password): # 登录方法,传入 username 与 passwordself.login_username().send_keys(username)self.login_password().send_keys(password)self.login_button().click()

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

# coding:utf-8from time import sleepfrom 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]")# 下单成功Casedef place_order(self):self.product().click()self.ticket_book().click()self.book_date().send_keys("-06-16")self.to_order().click()sleep(2)element = self.pay_off()self.driver.execute_script('arguments[0].click()', element)sleep(2)

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

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

代码示例如下:

# coding:utf-8import unittestfrom time import sleepfrom selenium import webdriverfrom pages.home_page import HomePagefrom pages.login_page import LoginPagefrom pages.order_page import OrderPage'''1、初始化 - 打开浏览器,设置浏览器大小2、最终操作 - 关闭浏览器3、用例部分 - 登录 与 购买操作、下订单、支付'''class TestTravel(unittest.TestCase):@classmethoddef setUpClass(cls):# 每个测试类在加载之前执行一次 setUpClass ,初始化方法cls.driver = webdriver.Chrome()cls.driver.maximize_window()def test_a_order(self):#初始化参数username = '13500000001'password = 'Success@'#初始化界面home_page = HomePage(driver=self.driver, path="http://django./#/")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()@classmethoddef tearDownClass(cls):cls.driver.quit() # 彻底退出浏览器if __name__ == '__main__':unittest.main()

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

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

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。