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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
万叶集
🎉 隐约雷鸣阴霾天空。 🎉
🎉 但盼风雨来能留你在此。 🎉


前言
✌ 作者简介渴望力量的哈士奇 ✌大家可以叫我 🐶哈士奇🐶 一位致力于 TFS 赋能的博主 ✌
🏆 CSDN博客专家认证、新星计划第三季全栈赛道 top_1 、华为云享专家、阿里云专家博主 🏆
📫 如果文章知识点有错误的地方请指正和大家一起学习一起进步👀
💬 人生格言优于别人,并不高贵,真正的高贵应该是优于过去的自己。💬
🔥 如果感觉博主的文章还不错的话还请👍关注、点赞、收藏三连支持👍一下博主哦


专栏系列点击解锁学习路线指引知识定位
🔥Python全栈白皮书🔥 零基础入门篇 以浅显易懂的方式轻松入门让你彻底爱上Python的魅力。
语法进阶篇 主要围绕多线程编程、正则表达式学习、含贴近实战的项目练习 。
自动化办公篇 实现日常办公软件的自动化操作节省时间、提高办公效率。
自动化测试实战篇 从实战的角度出发先人一步快速转型测试开发工程师。
数据库开发实战篇 更新中
爬虫入门与实战 更新中
数据分析篇 更新中
前端入门+flask 全栈篇 更新中
django+vue全栈篇 更新中
拓展-人工智能入门 更新中
网络安全之路 踩坑篇 记录学习及演练过程中遇到的坑便于后来居上者
网安知识扫盲篇 三天打鱼不深入了解原理只会让你成为脚本小子。
vulhub靶场漏洞复现 让漏洞复现变得简单让安全研究者更加专注于漏洞原理本身。
shell编程篇 不涉及linux基础最终案例会偏向于安全加固方向。 [待完结]
WEB漏洞攻防篇 2021年9月3日停止更新转战先知社区等安全社区及小密圈
渗透工具使用集锦 2021年9月3日停止更新转战先知社区等安全社区及小密圈
点点点工程师 测试神器 - Charles 软件测试数据包抓包分析神器
测试神器 - Fiddler 一文学会 fiddle 学不会倒立吃翔稀得
测试神器 - Jmeter 不仅是性能测试神器更可用于搭建轻量级接口自动化测试框架。
RobotFrameWork Python实现的自动化测试利器该篇章仅介绍UI自动化部分。
Java实现UI自动化 文档写于2016年Java实现的UI自动化仍有借鉴意义。
MonkeyRunner 该工具目前的应用场景已不多文档已删为了排版好看才留着。


文章目录

在使用 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-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

代码示例如下

# 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

代码示例如下

# 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

# 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的改造

代码示例如下

# 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秒的时间



阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: python

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