• Selenium4+Python3系列(十) - Page Object设计模式


    前言

    Page Object(PO)模式,是Selenium实战中最为流行,并且被自动化测试同学所熟悉和推崇的一种设计模式之一。在设计测试时,把页面元素定位和元素操作方法按照页面抽象出来,分离成一定的对象,然后再进行组织。

    相信每个做自动化测试的同学,一定会遇到这样一个非常头疼的问题,那就是页面变化,如果没有使用Page Object设计模式,这就意味着以前的定位元素方法不能用了,需要重新修改元素定位方式。你需要一个一个从测试脚本中把需要修改的元素定位方式找出来,然后再进行修改。这势必会使脚本维护的成本变高,显然这样的自动化脚本就不会有人愿意使用。

    那这时我们使用Page Object模式就可以解决这个问题了。

    PageObject 的优点

    • 减少代码冗余
    • 业务和实现分离
    • 降低代码维护成本

    Page Object模式

    Page Object 见名知意,就是页面对象,并将页面元素定位方法和元素操作进行分离。

    在实际自动化测试实战过程中,我们一般对脚本的实现分为三层:

    • 对象层:用于存放页面元素定位和控件操作。
    • 逻辑层:则是一些封装好的功能用例模块。
    • 业务层:则是我们真正的测试用例的操作部分。

    使用 Page Object 类来分离页面元素

    对象层

    首先我们新建一个类login_page,登录页面内编写需要操作的元素定位方式和控件操作,具体代码示例如下:

    python
    # -*- coding: utf-8 -*-
    """
    # @Time    : 2022/11/26 22:16
    # @Author  : longrong.lang
    # @FileName: login_page.py
    # @Software: PyCharm
    # @Blog    :https://www.cnblogs.com/longronglang/
    # @Motto:ABC(Always Be Coding)
    """
    import time
    
    from selenium.webdriver.common.by import By
    
    
    class LoginPage:
        """
        封装元素定位及控件
        """
    
        def __int__(self, driver):
            self.driver = driver
    
        # 打开浏览器
        def open(self, url):
            self.driver.get(url)
    
        # 用户名元素定位
        def user_name(self):
            return self.driver.find_element(By.CSS_SELECTOR, "input[type='text']")
    
        # 密码元素定位
        def pass_word(self):
            return self.driver.find_element(By.CSS_SELECTOR, "input[type='password']")
    
        # 登录元素定位
        def login_btn(self):
            return self.driver.find_element(By.CSS_SELECTOR, "button[name='submit']")
    
        # 错误提示
        def error_msg(self):
            return self.driver.find_element(By.ID, "alert")
    
        # 输入用户名
        def send_username(self, username):
            self.user_name().clear()
            self.user_name().send_keys(username)
    
        # 输入密码
        def send_password(self, password):
            self.pass_word().clear()
            self.pass_word().send_keys(password)
    
        # 点击登录
        def click_login(self):
            self.login_btn().click()
    
        # 获取错误提示
        def get_errorMsg(self):
            time.sleep(1)
            return self.error_msg().text
    
        # 退出浏览器
        def quit(self):
            self.driver.quit()

    这里我只对用户名和密码输入框进行了封装,有兴趣的同学也可以接着进行全部元素操作封装。

    操作层

    我们再新建一个类login_action,用于登录逻辑的封装,供业务层调用,具体代码示例如下:

    python
    # -*- coding: utf-8 -*-
    """
    # @Time    : 2022/11/26 22:33
    # @Author  : longrong.lang
    # @FileName: login_action.py
    # @Software: PyCharm
    # @Blog    :https://www.cnblogs.com/longronglang/
    # @Motto:ABC(Always Be Coding)
    """
    import time
    
    from pageobject.login_page import LoginPage
    
    
    class LoginAction(LoginPage):
    
        def login(self, username, password, expected):
            self.open("http://localhost:8080/login")
            self.send_username(username)
            self.send_password(password)
            self.click_login()
            time.sleep(1)
            msg = self.get_errorMsg()
            assert msg == expected
            self.quit()

    业务层

    最后我们新建一个类test_login,用于业务层的封装,具体代码示例如下:

    python
    # -*- coding: utf-8 -*-
    """
    # @Time    : 2022/11/26 22:43
    # @Author  : longrong.lang
    # @FileName: test_login.py
    # @Software: PyCharm
    # @Blog    :https://www.cnblogs.com/longronglang/
    # @Motto:ABC(Always Be Coding)
    """
    from pageobject.login_action import LoginAction
    from selenium import webdriver
    from webdriver_manager.chrome import ChromeDriverManager
    
    
    class TestLogin(LoginAction):
        def test_login(self):
            self.driver = webdriver.Chrome(ChromeDriverManager().install())
            self.driver.maximize_window()
            self.driver.implicitly_wait(5)
            self.login("username", "pwd", "登录失败!")

    小结

    虽然该实现方法看上去复杂多了,但其中的设计好处是不同层关心不同的问题。页面对象只关心元素的定位,测试用例只关心测试数据。

    login_page类中主要对登录页面上元素进行封装,使其成为具体的操作方法。如对用户名、密码框都封装成方法,然后定义login(self, username, password, expected)方法将单个元素操作组成一个完整的动作,包含输入用户名、密码并点击登录按钮等。

    使用时将driver、username、pwd、expected作为函数的入参,这样的方法具有很强的可重用性。

    最后使用test_login()方法进行用户操作行为,现在只关心用哪个浏览器、登录的用户名和密码是什么,至少输入框、按钮是如何定位的,则不关心。即实现了不同层关心不同问题。如果再有定位元素变化,只需login_page这个类维护即可,显然方便了很多。


    __EOF__

  • 本文作者: 久曲健的测试窝
  • 本文链接: https://www.cnblogs.com/longronglang/p/16930414.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    Live800:一个优秀的客服应具备哪些技能?
    干货︱部分领域数字孪生白皮书及报告汇总(附下载)
    S2B2C商城系统平台功能模块分析,加速医药制造企业数字化转型落地
    深拷贝与浅拷贝
    高教社杯数模竞赛特辑论文篇-2023年E题:基于小波变换和背包模型的小浪底水库最优监测方案研究(附获奖论文及Python代码实现)
    PDF编辑阅读 PDF Expert v3.5.2
    微店商品详情API接口:获取微店商品主题、价格、销量
    【网站架构】如何长久运行升级?高可用部署只是基础,巡检、监控、应用数据备份、日志、灰度发布
    Windows 11又双叒出现Bug,导致截图工具崩溃
    POSIX
  • 原文地址:https://www.cnblogs.com/longronglang/p/16930414.html