POM思想的理解与示例

目录

​​

[POM(Page Object Model)核心理解​​](#POM(Page Object Model)核心理解)

[​​一、POM 的核心原则​​](#一、POM 的核心原则)

[​​二、完整示例(python + pytest)](#二、完整示例(python + pytest))

1、项目结构

2、基础页面类(封装action等

3、登录页面类(login_page.py)

4、主页类(dashboard_page.py)

5、pytest夹具配置(confest.py)

6、测试用例

[​​三、POM 的优势​​](#三、POM 的优势)

​​总结​​


​​

POM(Page Object Model)核心理解​​

​​POM(页面对象模型)​ ​ 是自动化测试中广泛使用的设计模式,它将​​页面元素定位​ ​和​​操作逻辑​​封装成独立的类,使测试脚本更易维护、复用和协作。

以下是其核心思想和实现示例:


​​一、POM 的核心原则​​

  1. ​​分离元素定位与测试逻辑​​

    • 元素选择器(如 #username)只存在于 Page 类中,测试脚本只调用方法(如 login())。
  2. ​​一个页面一个类​​

    • 每个页面(如登录页、主页)对应一个独立的类。
  3. ​​方法代表用户操作​​

    • 如 clickSubmitButton()而非直接写 page.click('button')。
  4. ​​返回其他 Page 对象​​

    • 操作后返回新页面对象(如登录后返回主页对象)。

​​二、完整示例(python + pytest)

1、项目结构

tests/
├── features/
│ ├── login.feature # Gherkin 场景(与JS版相同)
│ └── steps/
│ └── login_steps.py # 步骤定义(Python实现)
├── pages/
│ ├── base_page.py # 基础页面类
│ ├── login_page.py # 登录页
│ └── dashboard_page.py # 主页
├── conftest.py # pytest 夹具配置
└── requirements.txt # 依赖文件​
​

2、基础页面类(封装action等
python 复制代码
# pages/base_page.py
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class BasePage:
    def __init__(self, driver):
        self.driver = driver
        self.wait = WebDriverWait(driver, 10)  # 显式等待

    def click(self, locator):
        """通用点击方法"""
        self.wait.until(EC.element_to_be_clickable(locator)).click()

    def type(self, locator, text):
        """通用输入方法"""
        self.wait.until(EC.visibility_of_element_located(locator)).send_keys(text)

    def navigate_to(self, url):
        """导航到指定URL"""
        self.driver.get(url)
        self.wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
3、登录页面类(login_page.py)
python 复制代码
# pages/login_page.py
from pages.base_page import BasePage
from selenium.webdriver.common.by import By

class LoginPage(BasePage):
    # 元素定位器(元组形式,兼容By类)
    USERNAME_INPUT = (By.ID, "username")
    PASSWORD_INPUT = (By.CSS_SELECTOR, "#password")
    LOGIN_BUTTON = (By.XPATH, "//button[@type='submit']")
    ERROR_MESSAGE = (By.CLASS_NAME, "error-message")

    def enter_username(self, username):
        self.type(self.USERNAME_INPUT, username)
        return self  # 支持链式调用

    def enter_password(self, password):
        self.type(self.PASSWORD_INPUT, password)
        return self

    def click_login(self):
        self.click(self.LOGIN_BUTTON)
        from pages.dashboard_page import DashboardPage  # 延迟导入避免循环依赖
        return DashboardPage(self.driver)  # 返回新页面对象

    def get_error_message(self):
        return self.wait.until(
            EC.visibility_of_element_located(self.ERROR_MESSAGE)
        ).text

    # 完整登录流程
    def login(self, username, password):
        return (
            self.enter_username(username)
            .enter_password(password)
            .click_login()
        )
4、主页类(dashboard_page.py)
python 复制代码
# pages/dashboard_page.py
from pages.base_page import BasePage
from selenium.webdriver.common.by import By

class DashboardPage(BasePage):
    WELCOME_MESSAGE = (By.CSS_SELECTOR, ".welcome-text")
    LOGOUT_BUTTON = (By.ID, "logout-btn")

    def get_welcome_message(self):
        return self.wait.until(
            EC.visibility_of_element_located(self.WELCOME_MESSAGE)
        ).text

    def click_logout(self):
        self.click(self.LOGOUT_BUTTON)
        from pages.login_page import LoginPage  # 延迟导入
        return LoginPage(self.driver)
5、pytest夹具配置(confest.py)
python 复制代码
# conftest.py
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

@pytest.fixture(scope="module")
def driver():
    """共享浏览器实例"""
    options = Options()
    options.headless = True  # 无头模式
    driver = webdriver.Chrome(options=options)
    yield driver
    driver.quit()  # 测试结束后关闭浏览器

@pytest.fixture
def login_page(driver):
    """登录页夹具"""
    from pages.login_page import LoginPage
    return LoginPage(driver)
6、测试用例
python 复制代码
# tests/test_login.py
def test_successful_login(login_page):
    dashboard_page = login_page.login("admin", "admin123")
    assert "Welcome, admin" in dashboard_page.get_welcome_message()

def test_failed_login(login_page):
    login_page.enter_username("admin").enter_password("wrong")
    login_page.click_login()
    assert "Invalid password" in login_page.get_error_message()

​​三、POM 的优势​​

优势 说明
​​可维护性​​ 元素选择器变更只需修改 Page 类,无需修改测试脚本。
​​复用性​​ 多个测试场景可复用同一 Page 类的方法(如 login())。
​​可读性​​ 测试脚本读起来像用户手册(如 loginPage.login())。
​​协作友好​​ 开发与测试可并行:开发提供 Page 类,测试编写 Gherkin 场景。

​​总结​​

POM 的核心是 ​​"将页面抽象为对象,操作抽象为方法"​​。通过分层设计:

  1. ​​Page 类​​:封装元素和操作

  2. ​​测试脚本​​:只关心业务逻辑(如"登录成功")

  3. ​​Gherkin​​:描述行为而非实现

这种模式让自动化测试代码更健壮、更易应对需求变更。

相关推荐
jktantan2 小时前
Vue keep-alive 切标签后滚动位置回顶?因为 onDeactivated 里读到的 scrollTop 是 0
前端·javascript·vue.js
总要学点什么2 小时前
第89篇:三维特效-螺旋圆效果——让螺旋臂卷起一圈圈外扩的涟漪
开发语言·javascript·ecmascript·webgl·cesium·空间分析·1024程序员节
前端精髓2 小时前
结构化输出with_structured_output(抽卡)
python·langchain
2601_962885723 小时前
quotes 字段全解:涨跌幅、振幅、换手率的口径与单位
java·前端·spring
excel3 小时前
encodeURI 和 encodeURIComponent 有什么区别?
前端
前端精髓3 小时前
调用openrouter的免费API模型
java·前端·javascript
尹人入圣3 小时前
目前热门的IP驱动产业新场景新工具
网络·python·网络协议·tcp/ip
赛博守夜人4 小时前
AI安全攻防与治理之十四:AI 安全测试不能脱离传统安全,Web、API、移动端与模型攻击面的组合拳
前端·人工智能·安全
开开心心_Every4 小时前
快速隐藏程序工具自定义快捷键一键切换
java·开发语言·前端·spring·智能手机·word·intellij-idea
Nuanyt4 小时前
Agent 学习笔记(下篇三):上线工程、进阶选择与操作界面(Stage 7 / 7.5 / 8 + 延伸路线)
笔记·python·学习·memory·aiagent·harness