• Python —— UI自动化之Page Object模式


    1、Page Object模式简介

    1、二层模型

            Page Object Model(页面对象模型), 或者也可称之为POM。在UI自动化测试广泛使用的一种分层设计 模式。核心是通过页面层封装所有的页面元素及操作,测试用例层通过调用页面层操作组装业务逻辑。

    1、实战 

    目录如下:

    home_page.py文件的内容:

    1. from selenium.webdriver.common.by import By
    2. class HomePage:
    3. login_link_locator = (By.LINK_TEXT, '登录')
    4. def click_login_link(self,driver):
    5. # 前面加*号是解包的操作,因为login_link_locator是元组
    6. driver.find_element(*self.login_link_locator).click()

    login_page.py文件的内容:

    1. from time import sleep
    2. from selenium import webdriver
    3. from selenium.webdriver.common.by import By
    4. class LoginPage:
    5. #属性->元素定位信息(元素定位方法+元素定位值)-元组类型
    6. phone_input_locator = (By.XPATH,'//input[@placeholder="请输入手机号/用户名"]')
    7. pwd_input_locator = (By.XPATH,'//input[@placeholder="请输入密码"]')
    8. login_button_locator = (By.CLASS_NAME,'login-button')
    9. #操作->元素行为,登录操作
    10. def page_login(self,driver,phone,pwd):
    11. # *self.phone_input_locator 前面的*号是解包使用的
    12. driver.find_element(*self.phone_input_locator).send_keys(phone)
    13. driver.find_element(*self.pwd_input_locator).send_keys(pwd)
    14. sleep(2)
    15. driver.find_element(*self.login_button_locator).click()

    登录案例 - PO.py的文件内容:

    1. from selenium import webdriver
    2. from d6_JavaScript处理.testcases.home_page import HomePage
    3. from d6_JavaScript处理.testcases.login_page import LoginPage
    4. driver = webdriver.Chrome()
    5. driver.maximize_window()
    6. driver.get("http://mall.banan.com:3344/")
    7. HomePage().click_login_link(driver)
    8. LoginPage().page_login(driver,"1723693766728","ydgcdlcb")

    2、三层模型

            基本的PO分层包括页面层与用例层,但是在编写页面层代码时会发现一个问题:页面中存在非常多相同 的操作方法,比如都需要等待元素、获取元素属性/文本信息、页面滚动等等,每个页面层类都需要有相 同的代码,代码存在非常多冗余。我们可以把这些【公共】的页面操作方法给提取出来放到一个类中进 行维护,其他的页面类共用该类中的操作方法即可(通过继承实现)。

    UI自动化断言:
            断言是自动化测试不可缺少的部分,当我们使用测试脚本对业务逻辑进行操作时,需要检查交互操作之 后结果的正确性,此时需要通过断言机制来进行验证。

            Pytest测试框架内置丰富的断言,通过assert语句即可,常见的断言方法比较包括:

    • 比较相等
    assert a == b
    • 比较大小(大于/小于/大于等于/小于等于)
    assert a > b
    • 内容包含/内容不包含
    assert a in b
    • 验证表达式是否为真
    assert condition
    UI自动化常见的断言条件包括:
    • 通过当前页面的URL地址

    • 通过当前页面的标题
    • 通过当前页面的提示文本信息
    • 通过当前页面的某些元素变化/显示

    一句话总结:通过肉眼观察页面的变化检查

    3、三层模型实战

    思路:抽取一个公共类,这个类中可以写公共页面的属性和函数,也可以写每次都要使用的属性,从UI自动化的角度来看,浏览器驱动是每次执行用例都会用到的,所以也可以抽取出来。

    三层模型的文件目录如下:

    base_page.py文件中的内容:

    1. import os
    2. from selenium.webdriver import ActionChains
    3. from selenium.webdriver.support import expected_conditions as EC
    4. from selenium.webdriver.support.wait import WebDriverWait
    5. # BasePage 用来存放所有页面类的公共部分,一些公共的操作(显式封装)
    6. class BasePage:
    7. def __init__(self,driver):
    8. self.driver = driver
    9. # 封装的意思:把相同类似的代码放到一个函数里面,重复使用
    10. # locator是元组的类型
    11. def wait_element_clickable(self, locator):
    12. web_element = WebDriverWait(self.driver,5,0.5).until(EC.element_to_be_clickable(locator))
    13. return web_element
    14. def wait_element_visible(self, locator):
    15. # web_element代表通过显示等待找到的元素
    16. web_element = WebDriverWait(self.driver,5,0.5).until(EC.visibility_of_element_located(locator))
    17. return web_element
    18. def wait_element_presence(self, locator):
    19. web_element = WebDriverWait(self.driver,5,0.5).until(EC.presence_of_all_elements_located(locator))
    20. return web_element
    21. # JavaScript进行元素的滚动
    22. def page_scroll(self,distance):
    23. self.driver.execute_script(f"document.documentElement.scrollTop={distance}")
    24. # JavaScript进行元素的点击
    25. def page_js_click(self,locator):
    26. element = self.wait_element_visible(self.driver,locator)
    27. self.driver.execute_script("arguments[0].click()",element)
    28. # JavaScript进行元素的移除
    29. def remove_element_attribute(self,locator,attribute):
    30. element = self.wait_element_visible(self.driver,locator)
    31. self.driver.execute_script(f"arguments[0].removeAttribute({attribute})", element)
    32. # 鼠标点击
    33. def mouse_click(self,locator):
    34. element = self.wait_element_visible(self.driver,locator)
    35. ActionChains(self.driver).click(element).perform()
    36. # 窗口切换
    37. def switch_to_window(self,title):
    38. handles = self.driver.window_handles
    39. for handle in handles:
    40. if self.driver.title == title:
    41. break
    42. else:
    43. self.driver.switch_to.window(handle)
    44. # 文件上传
    45. def update_file(self,filepath):
    46. os.system(f"test.exe {filepath}")

    home_page.py文件中的内容:

    1. import time
    2. from selenium.webdriver.common.by import By
    3. from selenium.webdriver.support import expected_conditions as EC
    4. from selenium.webdriver.support.wait import WebDriverWait
    5. from PO模式优化与自动化用例断言.common.base_page import BasePage
    6. class HomePage(BasePage):
    7. # 属性-登录链接
    8. login_link_locator = (By.LINK_TEXT,'登录')
    9. # 欢迎提示信息
    10. welcome_tips_locator = (By.XPATH,'//span[text()="欢迎来到天使的世界"]')
    11. welcome_tips_text_locator = (By.XPATH,'//span[@class="text"]')
    12. # 用户名
    13. username_text_locator = (By.XPATH,'//a[@class="link-name"]')
    14. def click_login_link(self):
    15. self.wait_element_clickable(self.login_link_locator).click()
    16. def is_display_welcome_tips(self):
    17. time.sleep(2)
    18. # return self.wait_element_clickable(self.welcome_tips_locator).is_displayed()
    19. return self.wait_element_clickable(self.welcome_tips_text_locator).text
    20. def get_username_text(self):
    21. return self.wait_element_visible(self.username_text_locator).text

    login_page.py文件中的内容: 

    1. import time
    2. from selenium.webdriver.common.by import By
    3. from selenium.webdriver.support import expected_conditions as EC
    4. from selenium.webdriver.support.wait import WebDriverWait
    5. from PO模式优化与自动化用例断言.common.base_page import BasePage
    6. class LoginPage(BasePage):
    7. # 属性->元素定位信息(元素定位方法+元素定位值)-元组类型
    8. phone_input_locator = (By.XPATH, '//input[@placeholder="请输入手机号/用户名"]')
    9. pwd_input_locator = (By.XPATH, '//input[@placeholder="请输入密码"]')
    10. login_button_locator = (By.CLASS_NAME, 'login-button')
    11. login_tips_locator = (By.XPATH, '//p[@class="el-message__content"]')
    12. def login(self,phone,pwd):
    13. # 因为继承了 basepage类,所以克不用再写driver参数
    14. # self.wait_element_visible(self.driver,self.phone_input_locator).send_keys("17728373518")
    15. self.wait_element_visible(self.phone_input_locator).send_keys(phone)
    16. self.wait_element_visible(self.pwd_input_locator).send_keys(pwd)
    17. self.wait_element_clickable(self.login_button_locator).click()
    18. time.sleep(3)
    19. def get_login_tips(self):
    20. # 这里比较文本内容
    21. return self.wait_element_visible(self.login_tips_locator).text
    22. print(self.wait_element_visible(self.login_tips_locator).text)

    test_login.py文件中的内容

    1. from selenium import webdriver
    2. from d7_PO模式优化与自动化用例断言.pageobjects.home_page import HomePage
    3. from d7_PO模式优化与自动化用例断言.pageobjects.login_page import LoginPage
    4. def test_login_success():
    5. driver = webdriver.Chrome()
    6. driver.get("http://mall.banan.com:3344/")
    7. driver.maximize_window()
    8. # 点击首页的登录操作
    9. homepage = HomePage(driver)
    10. homepage.click_login_link()
    11. # 在登陆页面进行登录操作
    12. loginpage = LoginPage(driver)
    13. loginpage.login("le_auto","le123456")
    14. # 断言检测测试是否成功(通过预期结果和实际结果的比较)
    15. # 检查点:1、欢迎页,如果函数的返回值为True,那么断言之后返回是通过的
    16. assert homepage.is_display_welcome_tips()
    17. # assert loginpage.get_login_tips() == '账号或者密码不正确'
    18. assert homepage.get_username_text() == 'lemon_auto'
    19. # 对登录结果的断言
    20. def test_login_uncorrect_username():
    21. driver = webdriver.Chrome()
    22. driver.get("http://mall.banan.com:3344/")
    23. homepage = HomePage(driver)
    24. homepage.click_login_link()
    25. # 在登陆页面进行登录操作
    26. loginpage = LoginPage(driver)
    27. loginpage.login("le_auto1", "le123456")
    28. # 页面登录过程中的提示信息断言
    29. assert loginpage.get_login_tips() == '账号或密码不正确'

    2、PO模式的优点

    1、提高测试用例的可读性

    2、提高测试用例可维护性

    3、减少代码重复

  • 相关阅读:
    Windows安装RabbitMQ
    编译原理7:语法分析、消除左递归、FIRST/FOLLOW集合
    详解SSL证书系列(1)什么是SSL证书?
    一年一度的科技狂欢盛会——2022亚马逊云科技re:Invent全球大会
    年已过半,年终立的Flag实现了几个?
    ExcelVBA把当前工作表导出为PDF文档
    Mysql高阶语句(二)
    python做小游戏之一小迷宫游戏
    Java练习 day2(LeetCode简单题15道)
    Git的概念和使用方法
  • 原文地址:https://blog.csdn.net/lzf_hlh/article/details/133972954