• WebUI 自动化测试的经典设计模式:PO


    一、PO 设计模式是什么

    • PO 的全称是 PageObject,是 Selenium 自动化测试项目开发实践的最佳设计模式之一,通过对界面元素和功能模块的封装减少冗余代码,有利于后期项目的维护。
    • 对页面对象进行抽象处理(页面对象包含:页面元素、button 点击、文本框输入、选项框选择等等)。使代码能在页面元素发生改变后,尽量减少测试脚本的改动量,最大程度支持代码的可重复性使用,同时使得测试框架结构合理、层次清晰、代码更加模块化,避免冗余、藕合性过高。

    二、PO 设计模式的优势


    (1)、优点说明

    测试的业务逻辑代码与页面的定位代码(如定位器、driver的相关操作或者其他的映射)相分离。

    该页面提供的方法或元素封装在一个独立的类或方法中, 而不是将这些方法或元素分散在整个测试的业务逻辑代码中。

    PO(PageObject) 对象作为一个与页面交互的接口,测试中需要与页面的 UI 进行交互时(测试数据、业务逻辑、页面操作对象已完成分离), 只需调用 PO(PageObject) 的方法,优点在于,如果页面的 UI 发生了更改,那么测试用例本身不需要更改, 只需更改 PO(PageObject)中的代码即可,有利于后期的维护。

    (2)、优点论证

    先来看下未使用 PO(PageObject) 设计模式下的代码,以网页版百度登录为例来说明。

    非 PO(PageObject) 模式下的代码如下,所有内容全部写在一个方法里。

    #test_login.py文件内容如下:
     
    def test_login():
        driver = webdriver.Chrome()
        driver.implicitly_wait(30)
        driver.maximize_window()
        base_url = "http://www.baidu.com/"
        driver.get(base_url)
     
        # 获取登录链接并在登录页面上填写登录数据
        driver.find_element(By.XPATH, '//*[@id="s-top-loginbtn"]').click()
        driver.find_element(By.ID, 'TANGRAM__PSP_11__footerULoginBtn').click()
        driver.find_element(By.ID, 'TANGRAM__PSP_11__userName').send_keys("test_user_name")
        driver.find_element(By.ID, 'TANGRAM__PSP_11__password').send_keys("test_user_password")
        driver.find_element(By.ID, "TANGRAM__PSP_11__submit").click()
     
        # 登录成功后验证页面是否包含文本:输入的登录用户名
        login_result = driver.find_element(By.XPATH, '//*[@id="s-top-username"]/span[2]').get_attribute("innerHTML")
        assert ("test_user_name" in login_result) is True

    存在的问题:

    • 测试方法与定位器 (在此实例中为By.ID)耦合过于严重. 如果测试的用户界面更改了其定位器或登录名的输入和处理方式, 则测试本身必须进行更改。
    • 在对登录页面的所有测试中, 同一个定位器会散布在其中。定位器的值也会耦合在业务逻辑中。

    PO(PageObject) 模式优化后的代码

    1、WebUI 自动化需要的 driver 基础操作

    #initial_driver.py文件内容如下:
     
    from selenium import webdriver
     
     
    def initial_driver(browser_name='chrome', target_url=''):
        browser = webdriver.Chrome
        browser_name = browser_name.lower()
        if browser_name not in {'chrome', 'firefox', 'ff', 'ie'}:
            browser_name = 'chrome'
        if browser_name == 'chrome':
            browser = webdriver.Chrome()
        elif browser_name in ('firefox', 'ff'):
            browser = webdriver.Firefox()
        elif browser_name == 'ie':
            browser = webdriver.Ie()
        browser.maximize_window()
        browser.implicitly_wait(30)
        browser.get(target_url)
        return browser

    2、登录页面元素获取

    #elements.py文件内容如下:
     
    from selenium.webdriver.common.by import By
     
    getloginBy = (By.XPATH, '//*[@id="s-top-loginbtn"]')
    getusername_loginBy = (By.ID, 'TANGRAM__PSP_11__footerULoginBtn')
    usernameBy = (By.ID, "TANGRAM__PSP_11__userName")
    passwordBy = (By.ID, "TANGRAM__PSP_11__password")
    signinBy = (By.ID, "TANGRAM__PSP_11__submit")
    homepageBy = (By.XPATH, '//*[@id="s-top-username"]/span[2]')
    test_url = "http://www.baidu.com"

    3、登录逻辑业务的封装

    #user_login.py文件内容如下:
     
    import elements,initial_driver
     
    def user_login(user_name, password):
        driver = initial_driver("chrome", elements.test_url)
        driver.find_element(*elements.getloginBy).click()
        driver.find_element(*elements.getusername_loginBy).click()
        driver.find_element(*elements.usernameBy).send_keys(user_name)
        driver.find_element(*elements.passwordBy).send_keys(password)
        driver.find_element(*elements.signinBy).click()
        target_text = driver.find_element(*elements.homepageBy).get_attribute("innerHTML")
        return target_text

    4、登录测试用例将使用以上3个页面对象

    #test_user_login.py文件内容如下:
     
    import user_login
     
    def test_user_login():
        target_text = user_login.user_login("username", "password")
        assert ("username" in target_text) is True

    可以发现,使用 PO(PageObject) 模式优化后的代码,有以下明显优势:


    1)、将以下3个模块进行了单独封装【降低了模块之间的耦合度,使层次更加清晰合理,便于后期维护与复用】

    • WebUI 中 driver 的常规操作。例如:测试浏览器的选择,满足了测试多样化的需求、浏览器窗口最大化操作等等。
    • 登录页面所有元素的 locator_type 和 locator_value,以及被测试的域名。
    • 完成业务逻辑代码流程的调用,并返回正常登录成功后主页面的文本内容。

    2)、如果前端页面有定位元素的 type 或 value 发生变化时,只需要修改 elements.py 文件中元素信息即可,不需要在测试业务模块中进行修改。

    三、PO 设计模式使用6大原则

    • 一个公共方法代表一个公共的服务,就是说一个方法代替页面上的某些操作。
    • PO(PageObject) 中的方法细节不会暴露在外,通过提供公共服务接口的形式提供给外部。
    • PO(PageObject) 本身是不应进行判断或断言. 判断和断言是测试的一部分, 应始终在测试的代码内, 而不是在 PO(PageObject)中,PO(PageObject) 用来包含页面的表示形式, 以及页面通过方法提供的服务, 但是与 PO(PageObject) 无关的测试代码不应包含在其中。
    • 当有页面跳转的操作时候,执行这个方法时应该在方法结束返回时能够跳转到另一个页面中。
    • 只需要对页面中我们需要的重要内容进行封装。
    • 页面中相同的组件,但是不同的操作应该要被拆成不同的方法进行封装。

    四、总结

    • 不要强迫自己一次封装到位,大多都是在项目实践中不断优化重构才使得脚本更加灵活和健全的,需经过一个不断迭代的过程。
    • PO(PageObject) 的设计方式具有很大的灵活性, 但是有一些基本规则可以使测试代码具有理想的可维护性。
    • PO(PageObject) 不一定需要代表整个页面,PO(PageObject) 设计模式可用于表示页面上的组件. 如果自动化测试中的页面包含多个组件, 则每个组件都有单独的页面对象, 这样有助于提高可维护性。

    欢迎关注【无量测试之道】公众号,回复【领取资源】
    Python编程学习资源干货、
    Python+Appium框架APP的UI自动化、
    Python+Selenium框架Web的UI自动化、
    Python+Unittest框架API自动化、

    资源和代码 免费送啦~
    文章下方有公众号二维码,可直接微信扫一扫关注即可。

    备注:我的个人公众号已正式开通,致力于测试技术的分享,包含:大数据测试、功能测试,测试开发,API接口自动化、测试运维、UI自动化测试等,微信搜索公众号:“无量测试之道”,或扫描下方二维码:

     

     添加关注,让我们一起共同成长!

  • 相关阅读:
    使用JavaScript发布订阅设计模式实现Ajax请求节流
    浏览器获取鼠标光标坐标
    JavaScript正则表达式
    git 入门以及git客户端的常用命令
    Chrome 开发者工具的使用介绍
    CSS3动画的使用以及优化
    移动的自适应方法
    新手如何编写测试用例
    Python接口测试入门
    MySQL的基本语句(一)
  • 原文地址:https://www.cnblogs.com/Wu13241454771/p/14609765.html
Copyright © 2020-2023  润新知