持续交付2.0

Page Object:自动化测试提效的利器之一

关注我,每天收获一个新技能!
关注我,每天收获一个新技能!

在 #自动化测试 实战中,最在的一个挑战就是"如何高效地维护自动化测试用例?"

而"页面对象(Page Object)"就是一个提高开发与维护效率的利器。

1
基本概念

Page Object 模式的核心在于将每个网页或者网页中的特定区域抽象成一个对象(也就是 Page Object 类)。这个类会封装与该页面相关的元素定位和操作方法。如此一来,当页面元素或者操作发生变动时,仅需修改对应的 Page Object 类,而不用对所有的测试用例进行改动。

2
优点

  • 可维护性
    :一旦页面元素的定位方式或者操作流程改变,只需在对应的 Page Object 类里修改元素定位或者操作方法,测试用例本身不受影响,从而降低了维护成本。
  • 可复用性
    :Page Object 类中的方法能够在多个测试用例中被复用,减少了代码的重复编写。比如,登录页面的输入用户名、密码和点击登录按钮的方法,能在不同的登录相关测试用例里重复使用,避免了代码的重复编写。
  • 可读性
    :测试用例里调用 Page Object 类的方法,代码会更具可读性,便于理解测试的具体步骤。例如,login_page.enter_username("testuser") 这种调用方式清晰地表明了操作的意图。

3
示例

假定要对一个登录页面进行自动化测试,下面是使用 Python 和 Selenium 实现的 Page Object 示例代码:


from selenium import webdriverfrom selenium.webdriver.common.by import By# 登录页面的 Page Object 类class LoginPage:    def __init__(self, driver):        self.driver = driver        self.username_input = (By.ID, "username")        self.password_input = (By.ID, "password")        self.login_button = (By.ID, "login-button")    def enter_username(self, username):        self.driver.find_element(*self.username_input).send_keys(username)    def enter_password(self, password):        self.driver.find_element(*self.password_input).send_keys(password)    def click_login_button(self):        self.driver.find_element(*self.login_button).click()# 测试用例def test_login():    driver = webdriver.Chrome()    driver.get("https://example.com/login")    login_page = LoginPage(driver)    login_page.enter_username("testuser")    login_page.enter_password("testpassword")    login_page.click_login_button()    # 后续可以添加断言来验证登录是否成功    driver.quit()if __name__ == "__main__":    test_login()

在上述代码中,LoginPage 类属于 Page Object 类,它封装了登录页面的元素定位和操作方法。

test_login 函数为测试用例,借助调用 LoginPage 这个页面类的方法来完成登录操作。

4
如何处理页面上的动态元素

在 Page Object 模式里处理页面上的动态元素,需要一些特殊的策略和技巧。动态元素指的是在页面加载、交互或者随着时间推移而改变位置、属性、内容的元素。下面为你介绍几种常见的处理方法:

1. 等待元素加载或状态改变

页面上的动态元素可能不会立即加载完成,或者需要一定时间来改变状态。可以使用显式等待机制,在元素满足特定条件(如可见、可点击等)后再进行操作。

以下是使用 Python 和 Selenium 实现显式等待的示例代码:

from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECclass MyPage:    def __init__(self, driver):        self.driver = driver    def wait_for_element(self, locator):        try:            # 等待最多10秒,直到元素可见            element = WebDriverWait(self.driver, 10).until(                EC.visibility_of_element_located(locator)            )            return element        except Exception as e:            print(f"元素等待失败: {e}")            return None    def click_dynamic_element(self):        # 假设动态元素的定位方式为ID,值为dynamic-element        locator = (By.ID, "dynamic-element")        element = self.wait_for_element(locator)        if element:            element.click()

2. 使用相对定位策略

动态元素的绝对位置可能会改变,但它与其他相对稳定元素的位置关系可能保持不变。可以利用这种相对关系来定位动态元素。

例如,动态元素总是位于某个固定元素的下方:

from selenium import webdriverfrom selenium.webdriver.common.by import Byclass MyPage:    def __init__(self, driver):        self.driver = driver    def find_dynamic_element_relative(self):        # 先找到固定元素        fixed_element = self.driver.find_element(By.ID, "fixed-element")        # 通过固定元素的位置来定位动态元素        dynamic_element = fixed_element.find_element(By.XPATH, "./following-sibling::div")        return dynamic_element

3. 根据元素属性或文本内容定位

动态元素的某些属性或文本内容可能是唯一且相对稳定的,可以根据这些信息来定位元素。

例如,根据元素的文本内容定位:

from selenium import webdriverfrom selenium.webdriver.common.by import Byclass MyPage:    def __init__(self, driver):        self.driver = driver    def find_dynamic_element_by_text(self):        # 根据文本内容定位元素        dynamic_element = self.driver.find_element(By.XPATH, "//button[text()='动态按钮']")        return dynamic_element

4. 定期轮询和重试机制

对于一些动态变化频繁的元素,可以采用定期轮询和重试机制,在一定时间内不断尝试定位元素,直到成功或超过最大重试次数。

import timefrom selenium import webdriverfrom selenium.webdriver.common.by import Byclass MyPage:    def __init__(self, driver):        self.driver = driver    def find_dynamic_element_with_retry(self):        max_retries = 5        retry_count = 0        while retry_count < max_retries:            try:                # 假设动态元素的定位方式为ID,值为dynamic-element                element = self.driver.find_element(By.ID, "dynamic-element")                return element            except Exception as e:                print(f"第 {retry_count + 1} 次尝试失败: {e}")                retry_count += 1                time.sleep        print("超过最大重试次数,未能找到元素")        return None

通过以上这些方法,可以有效地在 Page Object 模式中处理页面上的动态元素,提高自动化测试的稳定性和可靠性。

但也需要根据项目的实际情况和需求进行权衡和选择。

5
小结

Page Object 设计模式让自动化测试更高效、更易维护,你在实际项目中用过这种模式吗?欢迎留言分享你的经验或疑问!