目录
[POM(Page Object Model)核心理解](#POM(Page Object Model)核心理解)
[一、POM 的核心原则](#一、POM 的核心原则)
[二、完整示例(python + pytest)](#二、完整示例(python + pytest))
[三、POM 的优势](#三、POM 的优势)
POM(Page Object Model)核心理解
POM(页面对象模型) 是自动化测试中广泛使用的设计模式,它将页面元素定位 和操作逻辑封装成独立的类,使测试脚本更易维护、复用和协作。
以下是其核心思想和实现示例:
一、POM 的核心原则
-
分离元素定位与测试逻辑
- 元素选择器(如
#username
)只存在于 Page 类中,测试脚本只调用方法(如login()
)。
- 元素选择器(如
-
一个页面一个类
- 每个页面(如登录页、主页)对应一个独立的类。
-
方法代表用户操作
- 如
clickSubmitButton()
而非直接写page.click('button')
。
- 如
-
返回其他 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 的核心是 "将页面抽象为对象,操作抽象为方法"。通过分层设计:
-
Page 类:封装元素和操作
-
测试脚本:只关心业务逻辑(如"登录成功")
-
Gherkin:描述行为而非实现
这种模式让自动化测试代码更健壮、更易应对需求变更。