一、Page Object 模式的核心价值

1. 问题驱动
传统测试脚本将元素定位与操作逻辑混写在用例中,导致:

  • 维护灾难:页面元素变动需修改所有相关用例(如登录按钮ID变更需全局搜索替换)

  • 复用困难:相同操作逻辑无法跨用例共享(如登录流程重复编写)

  • 可读性差:业务逻辑被技术细节淹没(如page.locator("#login-btn").click()分散在多个步骤)

2. 解决方案
Page Object(PO)模式将页面抽象为类

  • 元素定位器 → 封装为类属性

  • 操作行为 → 封装为类方法

  • 业务流 → 通过方法组合实现

# 传统模式 vs PO模式对比  
# 传统:元素定位与操作耦合  
page.locator("#username").fill("user1")  
page.locator("#password").fill("pass1")  
page.locator("#login-btn").click()  

# PO模式:业务语义化  
login_page.enter_username("user1")  
login_page.enter_password("pass1")  
login_page.click_login()  

二、电商全流程PO架构设计

1. 系统分层架构

图片

2. 核心类设计
类名职责关键方法举例
LoginPage

登录页面操作封装

enter_credentials()

submit()

HomePage

首页导航与搜索

search_product()

view_cart()

ProductPage

商品详情操作

select_color()

add_to_cart()

CartPage

购物车管理

apply_coupon()

checkout()

OrderPage

订单结算流程

fill_address()

confirm_pay()

三、实战:电商登录-下单PO封装

1. 登录页封装(LoginPage)
class LoginPage:  
    def __init__(self, page):
        self.page = page  
        self.username_input = page.get_by_placeholder("手机号/邮箱")  # 使用面向用户定位器  
        self.password_input = page.get_by_label("密码")  
        self.submit_btn = page.get_by_role("button", name="登录")  

    def navigate_to_login(self):
        self.page.goto("https://mall.example.com/login")  

    def enter_credentials(self, username, password):
        self.username_input.fill(username)  
        self.password_input.fill(password)  

    def submit(self):
        self.submit_btn.click()  
        self.page.wait_for_url("**/dashboard")  # 显式等待导航完成  
2. 购物车页封装(CartPage)
class CartPage:  
    def __init__(self, page):
        self.page = page  
        self.coupon_field = page.locator("[data-testid='coupon-input']")  # 测试ID定位增强稳定性  
        self.apply_btn = page.get_by_text("应用优惠券")  

    def apply_coupon(self, code: str):
        self.coupon_field.fill(code)  
        self.apply_btn.click()  
        expect(self.page.get_by_text("优惠券已生效")).to_be_visible()  # 自动等待 + 断言  

    def checkout(self):
        self.page.get_by_role("button", name="结算").click()  
3. 业务流组合(测试用例层)
def test_e2e_order(login_page, home_page, cart_page):  
    # 登录 → 搜索 → 加购 → 结算  
    login_page.navigate_to_login()  
    login_page.enter_credentials("user1", "securePass123")  
    login_page.submit()  

    home_page.search_product("无线耳机")  
    home_page.select_first_product()  
    product_page.add_to_cart(quantity=2)  

    cart_page.apply_coupon("FESTIVAL2025")  
    cart_page.checkout()  
    order_page.confirm_payment()  
    assert order_page.get_order_status() == "支付成功"  

四、PO模式高级技巧

1. 复合操作封装

避免原子操作暴露,直接提供业务接口:

# 反例:调用方需知道操作细节  
login_page.enter_username("user1")  
login_page.enter_password("pass1")  
login_page.click_login()  

# 正例:业务语义封装  
login_page.login_with("user1", "pass1")  
2. 动态元素处理

使用Playwright的Locator API处理动态生成元素:

def get_product_element(self, name):  
    return self.page.locator(f".product-item:has-text('{name}')")  # 文本+CSS组合定位  
3. 多层级PO复用

通过页面嵌套实现复杂组件复用:

class HeaderComponent:  
    def __init__(self, page):
        self.search_bar = page.get_by_role("searchbox")  

    def search(self, keyword):
        self.search_bar.fill(keyword)  
        self.search_bar.press("Enter")  

class HomePage:
    def __init__(self, page):
        self.page = page  
        self.header = HeaderComponent(page)  # 复用头部组件  

五、Pytest集成与多用户测试

1. 测试隔离设计

利用Playwright的browser.new_context()实现用户会话隔离:

# conftest.py  
@pytest.fixture(scope="function")  
def user_context(playwright):  
    browser = playwright.chromium.launch()  
    context = browser.new_context(storage_state="user1_session.json")  # 复用登录态  
    yield context  
    context.close()  
2. 多用户并发测试

模拟用户并发抢购场景:

def test_concurrent_purchase(user_context_factory):  
    with ThreadPoolExecutor() as executor:  
        # 启动3个并发用户  
        futures = [  
            executor.submit(run_user_flow, user_context_factory("user1")),  
            executor.submit(run_user_flow, user_context_factory("user2")),  
            executor.submit(run_user_flow, user_context_factory("user3"))  
        ]  
        results = [f.result() for f in futures]  
    assert all("下单成功" in r for r in results)  

六、常见问题解决方案

问题场景根因PO模式解决方案

元素定位失效

页面结构调整或属性变更

集中维护定位器,修改仅影响PO类

异步加载导致操作失败

元素未就绪

PO方法内封装wait_for_selector

跨页面依赖管理复杂

页面跳转状态传递丢失

返回新页面对象(return OrderPage(self.page)

多语言版本兼容性差

文本定位器硬编码

抽取文本资源到独立配置文件

七、总结:PO模式的核心收益

  1. 可维护性:页面变更只需修改对应PO类,不影响200+测试用例

  2. 可读性:用例清晰表达业务意图(login_page.login_with() vs 5行定位代码)

  3. 复用性:购物车操作复用率达90%(加购/改数量/结算等)

  4. 扩展性:通过组件化设计支持新页面快速接入

终极实践建议

  • 原子操作 → 封装在PO方法内

  • 业务流程 → 组合PO方法实现

  • 验证逻辑 → 通过expect断言集成

  • 环境隔离 → 善用browser.new_context()

通过本实战,可构建日均执行5000+用例的电商测试框架,缺陷捕捉率提升40%,维护成本降低70%。


技术交流群

推荐阅读

DeepSeek实践指导手册、人工智能在软件测试中的应用、我们是如何测试人工智能的?

Deepseek52条喂饭指令

在本地部署属于自己的 DeepSeek 模型,搭建AI 应用平台

DeepSeek 大模型与智能体公开课,带你从零开始,掌握 AI 的核心技术,开启智能未来!

深度解析:如何通过DeepSeek优化软件测试开发工作,提升效率与准确度

DeepSeek、文心一言、Kimi、豆包、可灵……谁才是你的最佳AI助手?

从零到一:如何构建一个智能化测试平台?

DeepSeek-R1+ Ollama 本地部署全攻略

DeepSeek与Playwright结合:利用AI提升自动化测试脚本生成与覆盖率优化

DeepSeek大模型6大部署模式解析与探索测试开发技术赋能点

爱测智能化服务平台

测开人必看!0代码+AI驱动,测试效率飙升300% ——霍格沃兹测试开发学社‌重磅上新‌「爱测智能化服务平台」限时开放体验!

一码难求的Manus:智能体技术如何重构生产力?测试领域又有哪些新机遇?

开源工具

AppCrawler 开源版
https://github.com/seveniruby/AppCrawler

Hogwarts-Browser-Use 开源版
指导安装贴:hogwarts-browser-use - 开源项目 - 爱测-测试人社区


专业版 (7天免费试用)

自动遍历测试框架 AppCrawler 专业版
通用数据驱动测试框架 hogwarts-ddt 专业版
测试智能体框架 hogwarts-agent 专业版

学社提供的资源

教育官网:霍格沃兹测试开发学社
科技官网:测吧(北京)科技有限公司
火焰杯就业选拔赛:火焰杯就业选拔赛 - 霍格沃兹测试开发学社
火焰杯职业竞赛:火焰杯职业竞赛 - 霍格沃兹测试开发学社
学习路线图:霍格沃兹测试开发学社
公益社区论坛:爱测-测试人社区 - 软件测试开发爱好者的交流社区,交流范围涵盖软件测试、自动化测试、UI测试、接口测试、性能测试、安全测试、测试开发、测试平台、开源测试、测试教程、测试面试题、appium、selenium、jmeter、jenkins
公众号:霍格沃兹测试学院
视频号:霍格沃兹软件测试
ChatGPT体验地址:霍格沃兹测试开发学社

本套视频教程所有配套资料领取方式如下:

方式1:访问官网可下载:testingstudio.com
方式2:关注ceshiren.com社区
人工智能/AI/为什么测试工程师需要掌握AI_哔哩哔哩_bilibili
​adb命令:【霍格沃兹测试开发】adb命令零基础快速入门–深入理解掌握app自动化测试底层技术_哔哩哔哩_bilibili
Python语法:1.闭包和装饰器_哔哩哔哩_bilibili?
人工智能:人工智能在音频、视觉、多模态领域的应用_哔哩哔哩_bilibili
软件测试入门:【霍格沃兹测试开发】7小时速成!软件测试新手入门指南,轻松掌握测试技能!_哔哩哔哩_bilibili
测试开发:【霍格沃兹测试开发】面试BAT软件测试开发,你需要具备哪些技能?_哔哩哔哩_bilibili
面试题指导:【霍格沃兹测试开发】软件测试工程师如何拿到P5-P7高薪offer?_哔哩哔哩_bilibili
JMeter:JMeter从入门到精通全集 包含http/dubbo/Kafka压测、Grafana监控_哔哩哔哩_bilibili
Java测试框架:【软件测试】Java测试框架Junit5与Allure测试报告免费课_哔哩哔哩_bilibili
简历面试教程:软件测试工程师简历面试教程攻略–如何写出能进BAT大厂测开岗的优质简历?如何在面试中向HR要到更高薪资?如何拿到更高级别的offer?–持续更新!_哔哩哔哩_bilibili
Java:【软件测试教程】Java自动化测试平台开发入门篇之初识springboot_哔哩哔哩_bilibili?
java语言rest-assured:【霍格沃兹测试开发】java语言rest-assured框架进行接口测试实战_哔哩哔哩_bilibili
Java接口自动化:【软件测试】Java接口自动化测试之RestAssured_哔哩哔哩_bilibili
性能测试:【软件测试教程】高级性能测试-JMeter+InfluxDB+Grafana压测数据展示_哔哩哔哩_bilibili
Linux:Linux 中如何实时查看日志记录-【软件测试面试题】_哔哩哔哩_bilibili
接口测试:【软件测试教程】接口测试入门实战-基于企业微信api进行接口测试_哔哩哔哩_bilibili
APP自动化:【霍格沃兹测试开发】APP移动端自动化测试从入门到精通/Appium环境安装/元素定位与隐式等待(最全攻略)_哔哩哔哩_bilibili
MySQL:【软件测试教程】MySQL数据库基本增删改查与多表查询_哔哩哔哩_bilibili
postman:【软件测试】postman基础-发送post请求_哔哩哔哩_bilibili
性能实战:【软件测试教程】性能测试压测实战-JMeter+InfluxDB+Grafana压测数据展示_哔哩哔哩_bilibili
零基础入门:零基础快速入门软件测试的秘籍_哔哩哔哩_bilibili
Java-JUnit5:软件测试之Java测试框架JUnit5 L1_哔哩哔哩_bilibili
接口测试:【软件测试】App抓包实战练习-接口测试初级入门_哔哩哔哩_bilibili
接口mitmproxy工具:【软件测试教程】测开必备工具mitmproxy_哔哩哔哩_bilibili
pytest:1.pytest简介与安装-【软件测试实战教程】_哔哩哔哩_bilibili
app功能测试:14.app压力测试-【软件测试实战教程】_哔哩哔哩_bilibili
前端开发-vue:Vue生命周期_哔哩哔哩_bilibili
flask:Flask环境安装与配置_哔哩哔哩_bilibili
Appium:appium的基本介绍_哔哩哔哩_bilibili
精品课试听:1.接口测试价值与体系_哔哩哔哩_bilibili

Docker

Docker cp命令详解:在Docker容器和主机之间复制文件/文件夹

Docker pull 命令详解:从镜像仓库获取镜像

深入理解 Docker Run 命令:从入门到精通

Docker Exec 命令详解与实践指南

Docker Kill/Pause/Unpause命令详细使用指南

Docker Logs命令详解

Selenium

多任务一次搞定!selenium自动化复用浏览器技巧大揭秘

如何使用Selenium处理隐藏元素

软件测试/测试开发/全日制|selenium NoSuchDriverException问题解决

软件测试/人工智能|解决Selenium中的异常问题:“error sending request for url”

Python

使用Python爬取豆瓣电影影评:从数据收集到情感分析

如何使用 Python 实现十进制转二进制的程序

Python教程:如何获取颜色的RGB值

Python处理日期的利器—日期转换指南

Python字符串的编码与解码

 

更多推荐